about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorpawanbisht62 <36775517+pawanbisht62@users.noreply.github.com>2020-08-15 08:59:12 +0530
committerGitHub <noreply@github.com>2020-08-15 08:59:12 +0530
commitbab15885c0ab1230186cc45290c6d6c224289f6b (patch)
treece67bbf8ae8d6294671d8af43877cd9bc3a06be8 /src
parent7c4ef37e19c0f9f501c04dd7bb1d5b864f0b6a2b (diff)
parent668a34e0f438d4a950b9440239656d6755ad963c (diff)
downloadrust-bab15885c0ab1230186cc45290c6d6c224289f6b.tar.gz
rust-bab15885c0ab1230186cc45290c6d6c224289f6b.zip
Merge branch 'master' into feature/incorporate-tracing
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/builder.rs1
-rw-r--r--src/bootstrap/native.rs2
-rw-r--r--src/bootstrap/test.rs44
-rw-r--r--src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile7
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile7
-rwxr-xr-xsrc/ci/docker/scripts/freebsd-toolchain.sh24
-rw-r--r--src/ci/github-actions/ci.yml12
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md223
-rw-r--r--src/doc/rustc/src/targets/built-in.md15
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md14
-rw-r--r--src/librustc_arena/lib.rs6
-rw-r--r--src/librustc_ast/ast.rs275
-rw-r--r--src/librustc_ast/ast/tests.rs5
-rw-r--r--src/librustc_ast/crate_disambiguator.rs2
-rw-r--r--src/librustc_ast/lib.rs3
-rw-r--r--src/librustc_ast/node_id.rs14
-rw-r--r--src/librustc_ast/ptr.rs16
-rw-r--r--src/librustc_ast/token.rs18
-rw-r--r--src/librustc_ast/tokenstream.rs8
-rw-r--r--src/librustc_ast/util/parser.rs1
-rw-r--r--src/librustc_ast/visit.rs7
-rw-r--r--src/librustc_ast_passes/ast_validation.rs18
-rw-r--r--src/librustc_attr/Cargo.toml1
-rw-r--r--src/librustc_attr/builtin.rs29
-rw-r--r--src/librustc_attr/lib.rs3
-rw-r--r--src/librustc_builtin_macros/format.rs33
-rw-r--r--src/librustc_codegen_llvm/back/write.rs1
-rw-r--r--src/librustc_codegen_llvm/builder.rs55
-rw-r--r--src/librustc_codegen_llvm/consts.rs10
-rw-r--r--src/librustc_codegen_llvm/coverageinfo/mod.rs12
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs14
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs18
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs3
-rw-r--r--src/librustc_codegen_ssa/Cargo.toml1
-rw-r--r--src/librustc_codegen_ssa/back/link.rs54
-rw-r--r--src/librustc_codegen_ssa/back/linker.rs2
-rw-r--r--src/librustc_codegen_ssa/back/symbol_export.rs15
-rw-r--r--src/librustc_codegen_ssa/common.rs3
-rw-r--r--src/librustc_codegen_ssa/lib.rs10
-rw-r--r--src/librustc_codegen_ssa/mir/debuginfo.rs8
-rw-r--r--src/librustc_codegen_ssa/traits/coverageinfo.rs2
-rw-r--r--src/librustc_data_structures/Cargo.toml2
-rw-r--r--src/librustc_data_structures/fingerprint.rs48
-rw-r--r--src/librustc_data_structures/lib.rs3
-rw-r--r--src/librustc_data_structures/sorted_map.rs13
-rw-r--r--src/librustc_data_structures/svh.rs8
-rw-r--r--src/librustc_data_structures/temp_dir.rs34
-rw-r--r--src/librustc_data_structures/thin_vec.rs2
-rw-r--r--src/librustc_data_structures/transitive_relation.rs69
-rw-r--r--src/librustc_error_codes/error_codes/E0477.md3
-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_error_codes/error_codes/E0752.md18
-rw-r--r--src/librustc_errors/Cargo.toml1
-rw-r--r--src/librustc_errors/diagnostic.rs6
-rw-r--r--src/librustc_errors/json.rs12
-rw-r--r--src/librustc_errors/json/tests.rs4
-rw-r--r--src/librustc_errors/lib.rs17
-rw-r--r--src/librustc_errors/snippet.rs2
-rw-r--r--src/librustc_expand/Cargo.toml1
-rw-r--r--src/librustc_expand/lib.rs3
-rw-r--r--src/librustc_expand/mbe.rs10
-rw-r--r--src/librustc_expand/proc_macro_server.rs10
-rw-r--r--src/librustc_hir/arena.rs70
-rw-r--r--src/librustc_hir/def.rs10
-rw-r--r--src/librustc_hir/definitions.rs10
-rw-r--r--src/librustc_hir/hir.rs225
-rw-r--r--src/librustc_hir/hir_id.rs3
-rw-r--r--src/librustc_hir/lang_items.rs3
-rw-r--r--src/librustc_hir/lib.rs4
-rw-r--r--src/librustc_incremental/Cargo.toml1
-rw-r--r--src/librustc_incremental/persist/data.rs3
-rw-r--r--src/librustc_index/Cargo.toml3
-rw-r--r--src/librustc_index/bit_set.rs8
-rw-r--r--src/librustc_index/vec.rs33
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs8
-rw-r--r--src/librustc_infer/infer/free_regions.rs9
-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_macros/src/lib.rs7
-rw-r--r--src/librustc_macros/src/serialize.rs290
-rw-r--r--src/librustc_macros/src/symbols.rs2
-rw-r--r--src/librustc_metadata/Cargo.toml1
-rw-r--r--src/librustc_metadata/lib.rs2
-rw-r--r--src/librustc_metadata/rmeta/decoder.rs236
-rw-r--r--src/librustc_metadata/rmeta/encoder.rs210
-rw-r--r--src/librustc_metadata/rmeta/mod.rs33
-rw-r--r--src/librustc_metadata/rmeta/table.rs6
-rw-r--r--src/librustc_middle/arena.rs99
-rw-r--r--src/librustc_middle/dep_graph/dep_node.rs3
-rw-r--r--src/librustc_middle/hir/exports.rs2
-rw-r--r--src/librustc_middle/hir/place.rs10
-rw-r--r--src/librustc_middle/infer/canonical.rs13
-rw-r--r--src/librustc_middle/lib.rs1
-rw-r--r--src/librustc_middle/middle/codegen_fn_attrs.rs4
-rw-r--r--src/librustc_middle/middle/cstore.rs14
-rw-r--r--src/librustc_middle/middle/dependency_format.rs2
-rw-r--r--src/librustc_middle/middle/exported_symbols.rs4
-rw-r--r--src/librustc_middle/middle/region.rs6
-rw-r--r--src/librustc_middle/middle/resolve_lifetime.rs6
-rw-r--r--src/librustc_middle/mir/interpret/allocation.rs32
-rw-r--r--src/librustc_middle/mir/interpret/error.rs173
-rw-r--r--src/librustc_middle/mir/interpret/mod.rs25
-rw-r--r--src/librustc_middle/mir/interpret/pointer.rs2
-rw-r--r--src/librustc_middle/mir/interpret/queries.rs23
-rw-r--r--src/librustc_middle/mir/interpret/value.rs8
-rw-r--r--src/librustc_middle/mir/mod.rs101
-rw-r--r--src/librustc_middle/mir/mono.rs2
-rw-r--r--src/librustc_middle/mir/predecessors.rs8
-rw-r--r--src/librustc_middle/mir/query.rs26
-rw-r--r--src/librustc_middle/mir/terminator/mod.rs4
-rw-r--r--src/librustc_middle/traits/mod.rs20
-rw-r--r--src/librustc_middle/traits/specialization_graph.rs4
-rw-r--r--src/librustc_middle/ty/adjustment.rs18
-rw-r--r--src/librustc_middle/ty/binding.rs2
-rw-r--r--src/librustc_middle/ty/cast.rs2
-rw-r--r--src/librustc_middle/ty/codec.rs535
-rw-r--r--src/librustc_middle/ty/consts.rs2
-rw-r--r--src/librustc_middle/ty/consts/kind.rs4
-rw-r--r--src/librustc_middle/ty/context.rs12
-rw-r--r--src/librustc_middle/ty/fast_reject.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.rs57
-rw-r--r--src/librustc_middle/ty/layout.rs28
-rw-r--r--src/librustc_middle/ty/list.rs11
-rw-r--r--src/librustc_middle/ty/mod.rs79
-rw-r--r--src/librustc_middle/ty/print/pretty.rs4
-rw-r--r--src/librustc_middle/ty/query/on_disk_cache.rs363
-rw-r--r--src/librustc_middle/ty/query/profiling_support.rs46
-rw-r--r--src/librustc_middle/ty/sty.rs50
-rw-r--r--src/librustc_middle/ty/subst.rs19
-rw-r--r--src/librustc_middle/ty/trait_def.rs2
-rw-r--r--src/librustc_middle/ty/util.rs2
-rw-r--r--src/librustc_mir/const_eval/error.rs170
-rw-r--r--src/librustc_mir/const_eval/eval_queries.rs15
-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/intern.rs3
-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/add_retag.rs38
-rw-r--r--src/librustc_mir/transform/const_prop.rs40
-rw-r--r--src/librustc_mir/transform/deaggregator.rs24
-rw-r--r--src/librustc_mir/transform/instrument_coverage.rs15
-rw-r--r--src/librustc_mir/transform/match_branches.rs93
-rw-r--r--src/librustc_mir/transform/mod.rs13
-rw-r--r--src/librustc_mir/transform/promote_consts.rs2
-rw-r--r--src/librustc_mir/transform/simplify_try.rs43
-rw-r--r--src/librustc_mir/transform/uninhabited_enum_branching.rs32
-rw-r--r--src/librustc_mir/transform/unreachable_prop.rs28
-rw-r--r--src/librustc_mir/util/pretty.rs6
-rw-r--r--src/librustc_mir_build/build/mod.rs12
-rw-r--r--src/librustc_parse/parser/expr.rs34
-rw-r--r--src/librustc_privacy/lib.rs17
-rw-r--r--src/librustc_query_system/Cargo.toml1
-rw-r--r--src/librustc_query_system/dep_graph/dep_node.rs5
-rw-r--r--src/librustc_query_system/dep_graph/graph.rs2
-rw-r--r--src/librustc_query_system/dep_graph/prev.rs2
-rw-r--r--src/librustc_query_system/dep_graph/serialized.rs2
-rw-r--r--src/librustc_query_system/lib.rs2
-rw-r--r--src/librustc_query_system/query/caches.rs9
-rw-r--r--src/librustc_query_system/query/plumbing.rs10
-rw-r--r--src/librustc_resolve/diagnostics.rs47
-rw-r--r--src/librustc_resolve/late/diagnostics.rs284
-rw-r--r--src/librustc_resolve/late/lifetimes.rs47
-rw-r--r--src/librustc_serialize/Cargo.toml3
-rw-r--r--src/librustc_serialize/collection_impls.rs158
-rw-r--r--src/librustc_serialize/json.rs123
-rw-r--r--src/librustc_serialize/lib.rs4
-rw-r--r--src/librustc_serialize/opaque.rs4
-rw-r--r--src/librustc_serialize/serialize.rs505
-rw-r--r--src/librustc_serialize/tests/json.rs21
-rw-r--r--src/librustc_serialize/tests/opaque.rs11
-rw-r--r--src/librustc_session/Cargo.toml1
-rw-r--r--src/librustc_session/config.rs10
-rw-r--r--src/librustc_session/lib.rs2
-rw-r--r--src/librustc_session/parse.rs3
-rw-r--r--src/librustc_session/search_paths.rs2
-rw-r--r--src/librustc_session/utils.rs2
-rw-r--r--src/librustc_span/def_id.rs73
-rw-r--r--src/librustc_span/edition.rs2
-rw-r--r--src/librustc_span/hygiene.rs49
-rw-r--r--src/librustc_span/lib.rs56
-rw-r--r--src/librustc_span/source_map.rs4
-rw-r--r--src/librustc_span/symbol.rs35
-rw-r--r--src/librustc_target/abi/mod.rs6
-rw-r--r--src/librustc_target/asm/mod.rs42
-rw-r--r--src/librustc_target/lib.rs3
-rw-r--r--src/librustc_target/spec/abi.rs4
-rw-r--r--src/librustc_target/spec/mod.rs8
-rw-r--r--src/librustc_trait_selection/traits/auto_trait.rs7
-rw-r--r--src/librustc_trait_selection/traits/project.rs7
-rw-r--r--src/librustc_trait_selection/traits/query/normalize.rs6
-rw-r--r--src/librustc_typeck/astconv.rs52
-rw-r--r--src/librustc_typeck/check/cast.rs4
-rw-r--r--src/librustc_typeck/check/demand.rs1
-rw-r--r--src/librustc_typeck/check/method/probe.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs26
-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/coherence/inherent_impls.rs10
-rw-r--r--src/librustc_typeck/lib.rs5
-rw-r--r--src/librustdoc/clean/mod.rs30
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/clean/utils.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/librustdoc/passes/collect_trait_impls.rs1
-rw-r--r--src/rustllvm/ArchiveWrapper.cpp1
-rw-r--r--src/rustllvm/CoverageMappingWrapper.cpp5
-rw-r--r--src/rustllvm/PassWrapper.cpp2
-rw-r--r--src/rustllvm/RustWrapper.cpp2
-rw-r--r--src/test/codegen-units/polymorphization/pr-75255.rs52
-rw-r--r--src/test/codegen/consts.rs4
-rw-r--r--src/test/codegen/naked-functions.rs4
-rw-r--r--src/test/debuginfo/function-arguments-naked.rs42
-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/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit66
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit66
-rw-r--r--src/test/mir-opt/matches_reduce_branches.rs13
-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/run-make-fulldeps/instrument-coverage/Makefile78
-rw-r--r--src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json2
-rw-r--r--src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt51
-rw-r--r--src/test/run-make-fulldeps/instrument-coverage/testprog.rs (renamed from src/test/run-make-fulldeps/instrument-coverage/main.rs)0
-rw-r--r--src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt4
-rw-r--r--src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile1
-rw-r--r--src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile1
-rw-r--r--src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile1
-rw-r--r--src/test/run-make-fulldeps/save-analysis/foo.rs116
-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/const-display.rs9
-rw-r--r--src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs25
-rw-r--r--src/test/ui-fulldeps/derive-no-std-not-supported.rs22
-rw-r--r--src/test/ui-fulldeps/deriving-encodable-decodable-box.rs7
-rw-r--r--src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs19
-rw-r--r--src/test/ui-fulldeps/deriving-global.rs32
-rw-r--r--src/test/ui-fulldeps/deriving-hygiene.rs8
-rw-r--r--src/test/ui-fulldeps/empty-struct-braces-derive.rs12
-rw-r--r--src/test/ui-fulldeps/issue-11881.rs21
-rw-r--r--src/test/ui-fulldeps/issue-14021.rs6
-rw-r--r--src/test/ui-fulldeps/issue-15924.rs9
-rw-r--r--src/test/ui-fulldeps/issue-24972.rs18
-rw-r--r--src/test/ui-fulldeps/issue-4016.rs3
-rw-r--r--src/test/ui-fulldeps/rustc_encodable_hygiene.rs6
-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/ast-json/ast-json-noexpand-output.stdout2
-rw-r--r--src/test/ui/ast-json/ast-json-output.stdout2
-rw-r--r--src/test/ui/const-generics/apit-with-const-param.rs6
-rw-r--r--src/test/ui/const-generics/apit-with-const-param.stderr11
-rw-r--r--src/test/ui/const-generics/argument_order.rs7
-rw-r--r--src/test/ui/const-generics/argument_order.stderr29
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.full.stderr18
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr27
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.rs16
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.stderr27
-rw-r--r--src/test/ui/const-generics/broken-mir-1.rs6
-rw-r--r--src/test/ui/const-generics/broken-mir-1.stderr11
-rw-r--r--src/test/ui/const-generics/broken-mir-2.rs6
-rw-r--r--src/test/ui/const-generics/broken-mir-2.stderr11
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.full.stderr11
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.min.stderr11
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.rs7
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.stderr20
-rw-r--r--src/test/ui/const-generics/coerce_unsized_array.rs7
-rw-r--r--src/test/ui/const-generics/concrete-const-as-fn-arg.rs6
-rw-r--r--src/test/ui/const-generics/concrete-const-as-fn-arg.stderr11
-rw-r--r--src/test/ui/const-generics/concrete-const-impl-method.rs6
-rw-r--r--src/test/ui/const-generics/concrete-const-impl-method.stderr11
-rw-r--r--src/test/ui/const-generics/condition-in-trait-const-arg.rs7
-rw-r--r--src/test/ui/const-generics/condition-in-trait-const-arg.stderr11
-rw-r--r--src/test/ui/const-generics/const-arg-in-fn.rs6
-rw-r--r--src/test/ui/const-generics/const-arg-in-fn.stderr11
-rw-r--r--src/test/ui/const-generics/const-arg-type-arg-misordered.rs2
-rw-r--r--src/test/ui/const-generics/const-arg-type-arg-misordered.stderr14
-rw-r--r--src/test/ui/const-generics/const-argument-non-static-lifetime.rs6
-rw-r--r--src/test/ui/const-generics/const-argument-non-static-lifetime.stderr11
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.full.stderr8
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.min.stderr8
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.rs7
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.stderr17
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.rs8
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.stderr11
-rw-r--r--src/test/ui/const-generics/const-generic-array-wrapper.rs6
-rw-r--r--src/test/ui/const-generics/const-generic-array-wrapper.stderr11
-rw-r--r--src/test/ui/const-generics/const-generic-type_name.rs6
-rw-r--r--src/test/ui/const-generics/const-generic-type_name.stderr11
-rw-r--r--src/test/ui/const-generics/const-param-after-const-literal-arg.rs6
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.rs4
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.stderr10
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.full.stderr (renamed from src/test/ui/const-generics/const-param-elided-lifetime.stderr)21
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.min.stderr78
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.rs14
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.full.stderr13
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.min.stderr13
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.rs7
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.stderr22
-rw-r--r--src/test/ui/const-generics/const-param-in-trait.rs10
-rw-r--r--src/test/ui/const-generics/const-param-in-trait.stderr11
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-const-param.full.stderr15
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr33
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-const-param.rs9
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr24
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr (renamed from src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr)15
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr18
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-type-param.rs7
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.full.stderr14
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.min.stderr14
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.rs7
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.stderr23
-rw-r--r--src/test/ui/const-generics/const-types.rs7
-rw-r--r--src/test/ui/const-generics/const-types.stderr11
-rw-r--r--src/test/ui/const-generics/defaults/complex-unord-param.rs20
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.rs12
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.stderr14
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.min.stderr8
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.none.stderr18
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.rs17
-rw-r--r--src/test/ui/const-generics/defaults/simple-defaults.rs15
-rw-r--r--src/test/ui/const-generics/derive-debug-array-wrapper.rs7
-rw-r--r--src/test/ui/const-generics/derive-debug-array-wrapper.stderr11
-rw-r--r--src/test/ui/const-generics/different_byref.full.stderr12
-rw-r--r--src/test/ui/const-generics/different_byref.min.stderr11
-rw-r--r--src/test/ui/const-generics/different_byref.rs12
-rw-r--r--src/test/ui/const-generics/different_byref.stderr21
-rw-r--r--src/test/ui/const-generics/different_byref_simple.full.stderr12
-rw-r--r--src/test/ui/const-generics/different_byref_simple.min.stderr12
-rw-r--r--src/test/ui/const-generics/different_byref_simple.rs14
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.full.stderr14
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.min.stderr20
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.rs8
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.stderr23
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.full.stderr8
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.min.stderr11
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.rs7
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.stderr17
-rw-r--r--src/test/ui/const-generics/fn-taking-const-generic-array.rs6
-rw-r--r--src/test/ui/const-generics/fn-taking-const-generic-array.stderr11
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.full.stderr9
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr27
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.rs9
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.stderr18
-rw-r--r--src/test/ui/const-generics/foreign-item-const-parameter.full.stderr (renamed from src/test/ui/const-generics/foreign-item-const-parameter.stderr)15
-rw-r--r--src/test/ui/const-generics/foreign-item-const-parameter.min.stderr19
-rw-r--r--src/test/ui/const-generics/foreign-item-const-parameter.rs7
-rw-r--r--src/test/ui/const-generics/impl-const-generic-struct.rs6
-rw-r--r--src/test/ui/const-generics/impl-const-generic-struct.stderr11
-rw-r--r--src/test/ui/const-generics/incorrect-number-of-const-args.full.stderr15
-rw-r--r--src/test/ui/const-generics/incorrect-number-of-const-args.min.stderr15
-rw-r--r--src/test/ui/const-generics/incorrect-number-of-const-args.rs7
-rw-r--r--src/test/ui/const-generics/incorrect-number-of-const-args.stderr24
-rw-r--r--src/test/ui/const-generics/infer_arg_from_pat.rs7
-rw-r--r--src/test/ui/const-generics/infer_arg_from_pat.stderr11
-rw-r--r--src/test/ui/const-generics/infer_arr_len_from_pat.rs7
-rw-r--r--src/test/ui/const-generics/infer_arr_len_from_pat.stderr11
-rw-r--r--src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.rs11
-rw-r--r--src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.stderr11
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.full.stderr18
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr18
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.rs13
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.stderr27
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr11
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs10
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.stderr11
-rw-r--r--src/test/ui/const-generics/issue-68104-print-stack-overflow.rs6
-rw-r--r--src/test/ui/const-generics/issue-70180-1-stalled_on.rs7
-rw-r--r--src/test/ui/const-generics/issue-70180-2-stalled_on.rs7
-rw-r--r--src/test/ui/const-generics/issue-71986.rs7
-rw-r--r--src/test/ui/const-generics/mut-ref-const-param-array.rs7
-rw-r--r--src/test/ui/const-generics/mut-ref-const-param-array.stderr11
-rw-r--r--src/test/ui/const-generics/nested-type.full.stderr (renamed from src/test/ui/const-generics/nested-type.stderr)60
-rw-r--r--src/test/ui/const-generics/nested-type.min.stderr175
-rw-r--r--src/test/ui/const-generics/nested-type.rs8
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr (renamed from src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.stderr)17
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr24
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs9
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr14
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr20
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.rs8
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.stderr23
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.full.stderr8
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.min.stderr11
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.rs7
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.stderr17
-rw-r--r--src/test/ui/const-generics/slice-const-param-mismatch.full.stderr (renamed from src/test/ui/const-generics/slice-const-param-mismatch.stderr)17
-rw-r--r--src/test/ui/const-generics/slice-const-param-mismatch.min.stderr20
-rw-r--r--src/test/ui/const-generics/slice-const-param-mismatch.rs16
-rw-r--r--src/test/ui/const-generics/slice-const-param.min.stderr20
-rw-r--r--src/test/ui/const-generics/slice-const-param.rs10
-rw-r--r--src/test/ui/const-generics/slice-const-param.stderr11
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.full.stderr9
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.min.stderr9
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.rs8
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.stderr5
-rw-r--r--src/test/ui/const-generics/trait-const-args.rs7
-rw-r--r--src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs6
-rw-r--r--src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr11
-rw-r--r--src/test/ui/const-generics/type-after-const-ok.rs10
-rw-r--r--src/test/ui/const-generics/type_of_anon_const.rs6
-rw-r--r--src/test/ui/const-generics/type_of_anon_const.stderr11
-rw-r--r--src/test/ui/const-generics/uninferred-consts.full.stderr11
-rw-r--r--src/test/ui/const-generics/uninferred-consts.min.stderr11
-rw-r--r--src/test/ui/const-generics/uninferred-consts.rs8
-rw-r--r--src/test/ui/const-generics/uninferred-consts.stderr20
-rw-r--r--src/test/ui/const-generics/unknown_adt.full.stderr (renamed from src/test/ui/const-generics/unknown_adt.stderr)2
-rw-r--r--src/test/ui/const-generics/unknown_adt.min.stderr9
-rw-r--r--src/test/ui/const-generics/unknown_adt.rs7
-rw-r--r--src/test/ui/const-generics/unused-const-param.rs6
-rw-r--r--src/test/ui/const-generics/unused-const-param.stderr11
-rw-r--r--src/test/ui/const-generics/unused_braces.fixed2
-rw-r--r--src/test/ui/const-generics/unused_braces.full.fixed17
-rw-r--r--src/test/ui/const-generics/unused_braces.full.stderr (renamed from src/test/ui/const-generics/unused_braces.stderr)4
-rw-r--r--src/test/ui/const-generics/unused_braces.min.fixed17
-rw-r--r--src/test/ui/const-generics/unused_braces.min.stderr14
-rw-r--r--src/test/ui/const-generics/unused_braces.rs6
-rw-r--r--src/test/ui/const-generics/wf-misc.full.stderr18
-rw-r--r--src/test/ui/const-generics/wf-misc.min.stderr18
-rw-r--r--src/test/ui/const-generics/wf-misc.rs14
-rw-r--r--src/test/ui/const-generics/wf-misc.stderr27
-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/error-codes/E0424.rs4
-rw-r--r--src/test/ui/error-codes/E0424.stderr40
-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-5099.rs9
-rw-r--r--src/test/ui/issues/issue-5099.stderr32
-rw-r--r--src/test/ui/issues/issue-59508-1.stderr2
-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/issues/issue-75307.rs3
-rw-r--r--src/test/ui/issues/issue-75307.stderr10
-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/mir/issue-75419-validation-impl-trait.rs13
-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/expr-as-stmt-2.rs10
-rw-r--r--src/test/ui/parser/expr-as-stmt-2.stderr33
-rw-r--r--src/test/ui/parser/expr-as-stmt.fixed6
-rw-r--r--src/test/ui/parser/expr-as-stmt.rs6
-rw-r--r--src/test/ui/parser/expr-as-stmt.stderr12
-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-2356.stderr27
-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-lifetime-specifier.rs8
-rw-r--r--src/test/ui/suggestions/missing-lifetime-specifier.stderr72
-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/unknown-llvm-arg.rs22
-rw-r--r--src/test/ui/unknown-llvm-arg.stderr1
-rw-r--r--src/test/ui/xcrate/xcrate-unit-struct.stderr5
-rw-r--r--src/tools/build-manifest/src/main.rs1
m---------src/tools/cargo0
-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
m---------src/tools/miri18
-rwxr-xr-xsrc/tools/publish_toolstate.py5
m---------src/tools/rls0
m---------src/tools/rustfmt23
-rw-r--r--src/tools/tidy/src/style.rs2
-rw-r--r--src/tools/tier-check/Cargo.toml8
-rw-r--r--src/tools/tier-check/src/main.rs52
708 files changed, 10715 insertions, 5701 deletions
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index e13a5f24653..4b0905bd6c1 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -404,6 +404,7 @@ impl<'a> Builder<'a> {
                 test::CrateLibrustc,
                 test::CrateRustdoc,
                 test::Linkcheck,
+                test::TierCheck,
                 test::Cargotest,
                 test::Cargo,
                 test::Rls,
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 48b2cc24d4c..3ab50e114c7 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -178,7 +178,7 @@ impl Step for Llvm {
             .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
             .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
 
-        if !target.contains("netbsd") {
+        if !target.contains("netbsd") && target != "aarch64-apple-darwin" {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
             // FIXME: Enable zlib on NetBSD too
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index bb5b9296c0a..11e2564305f 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -2043,3 +2043,47 @@ impl Step for Bootstrap {
         run.builder.ensure(Bootstrap);
     }
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct TierCheck {
+    pub compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl Step for TierCheck {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/tier-check")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host);
+        run.builder.ensure(TierCheck { compiler, target: run.host });
+    }
+
+    /// Tests the Platform Support page in the rustc book.
+    fn run(self, builder: &Builder<'_>) {
+        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
+        let mut cargo = tool::prepare_tool_cargo(
+            builder,
+            self.compiler,
+            Mode::ToolRustc,
+            self.target,
+            "run",
+            "src/tools/tier-check",
+            SourceType::InTree,
+            &[],
+        );
+        cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md"));
+        cargo.arg(&builder.rustc(self.compiler));
+        if builder.is_verbose() {
+            cargo.arg("--verbose");
+        }
+
+        builder.info("platform support check");
+        try_run(builder, &mut cargo.into());
+    }
+}
diff --git a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile
index 14af9b9efe8..bbbd632c6bb 100644
--- a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile
@@ -23,9 +23,9 @@ COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 ENV \
-    AR_i686_unknown_freebsd=i686-unknown-freebsd10-ar \
-    CC_i686_unknown_freebsd=i686-unknown-freebsd10-clang \
-    CXX_i686_unknown_freebsd=i686-unknown-freebsd10-clang++
+    AR_i686_unknown_freebsd=i686-unknown-freebsd11-ar \
+    CC_i686_unknown_freebsd=i686-unknown-freebsd11-clang \
+    CXX_i686_unknown_freebsd=i686-unknown-freebsd11-clang++
 
 ENV HOSTS=i686-unknown-freebsd
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
index 2372c0dad0a..766e6531c95 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
@@ -23,9 +23,9 @@ COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 ENV \
-    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
-    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-clang \
-    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-clang++
+    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd11-ar \
+    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd11-clang \
+    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd11-clang++
 
 ENV HOSTS=x86_64-unknown-freebsd
 
diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
index 6a596b3465f..cb507dced42 100644
--- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
@@ -19,8 +19,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+RUN mkdir -p /config
+RUN echo "[rust]" > /config/nopt-std-config.toml
+RUN echo "optimize = false" >> /config/nopt-std-config.toml
+
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
-ENV SCRIPT python3 ../x.py --stage 2 test
+ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
+  && python3 ../x.py --stage 2 test
 
 # FIXME(#59637) takes too long on CI right now
 ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
index fa769cac9c1..41e83c69e54 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
@@ -18,7 +18,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+RUN mkdir -p /config
+RUN echo "[rust]" > /config/nopt-std-config.toml
+RUN echo "optimize = false" >> /config/nopt-std-config.toml
+
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
   --disable-optimize-tests \
   --set rust.test-compare-mode
-ENV SCRIPT python3 ../x.py --stage 2 test
+ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
+  && python3 ../x.py --stage 2 test
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index 5670e10be23..b10263d5a26 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -5,8 +5,8 @@ set -eux
 
 arch=$1
 binutils_version=2.25.1
-freebsd_version=10.3
-triple=$arch-unknown-freebsd10
+freebsd_version=11.4
+triple=$arch-unknown-freebsd11
 sysroot=/usr/local/$triple
 
 hide_output() {
@@ -58,31 +58,17 @@ for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared; do
 done
 
 # Originally downloaded from:
-# https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
-URL=https://ci-mirrors.rust-lang.org/rustc/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz
+# URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
+URL=https://ci-mirrors.rust-lang.org/rustc/2020-08-09-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz
 curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
 
-# Fix up absolute symlinks from the system image.  This can be removed
-# for FreeBSD 11.  (If there's an easy way to make them relative
-# symlinks instead, feel free to change this.)
-set +x
-find "$sysroot" -type l | while read symlink_path; do
-  symlink_target=$(readlink "$symlink_path")
-  case $symlink_target in
-    (/*)
-      echo "Fixing symlink ${symlink_path} -> ${sysroot}${symlink_target}" >&2
-      ln -nfs "${sysroot}${symlink_target}" "${symlink_path}" ;;
-  esac
-done
-set -x
-
 # Clang can do cross-builds out of the box, if we give it the right
 # flags.  (The local binutils seem to work, but they set the ELF
 # header "OS/ABI" (EI_OSABI) field to SysV rather than FreeBSD, so
 # there might be other problems.)
 #
 # The --target option is last because the cross-build of LLVM uses
-# --target without an OS version ("-freebsd" vs. "-freebsd10").  This
+# --target without an OS version ("-freebsd" vs. "-freebsd11").  This
 # makes Clang default to libstdc++ (which no longer exists), and also
 # controls other features, like GNU-style symbol table hashing and
 # anything predicated on the version number in the __FreeBSD__
diff --git a/src/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/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index b603c7b231e..57013e9194b 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -11,6 +11,7 @@
         - [Deny-by-default lints](lints/listing/deny-by-default.md)
 - [Codegen options](codegen-options/index.md)
 - [JSON Output](json.md)
+- [Platform Support](platform-support.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
     - [Custom Targets](targets/custom.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
new file mode 100644
index 00000000000..b8d3c985cb5
--- /dev/null
+++ b/src/doc/rustc/src/platform-support.md
@@ -0,0 +1,223 @@
+# Platform Support
+
+<style type="text/css">
+    td code {
+        white-space: nowrap;
+    }
+</style>
+
+Support for different platforms are organized into three tiers, each with a
+different set of guarantees.
+
+Platforms are identified by their "target triple" which is the string to
+inform the compiler what kind of output should be produced. The columns in the
+tables below have the following meanings:
+
+* std:
+    * ✓ indicates the full standard library is available.
+    * \* indicates the target only supports [`no_std`] development.
+    * ? indicates the standard library support is unknown or a work-in-progress.
+* host: A ✓ indicates that `rustc` and `cargo` can run on the host platform.
+
+[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+
+## Tier 1
+
+Tier 1 platforms can be thought of as "guaranteed to work".
+Specifically they will each satisfy the following requirements:
+
+* Official binary releases are provided for the platform.
+* Automated testing is set up to run tests for the platform.
+* Landing changes to the `rust-lang/rust` repository's master branch is gated
+  on tests passing.
+* Documentation for how to use and how to build the platform is available.
+
+target | std | host | notes
+-------|-----|------|-------
+`i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
+`i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
+`i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`x86_64-apple-darwin` | ✓ | ✓ | 64-bit OSX (10.7+, Lion+)
+`x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+)
+`x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
+`x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
+
+## Tier 2
+
+Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
+are not run so it's not guaranteed to produce a working build, but platforms
+often work to quite a good degree and patches are always welcome!
+Specifically, these platforms are required to have each of the following:
+
+* Official binary releases are provided for the platform.
+* Automated building is set up, but may not be running tests.
+* Landing changes to the `rust-lang/rust` repository's master branch is gated on
+    platforms **building**. For some platforms only the standard library is
+    compiled, but for others `rustc` and `cargo` are too.
+
+target | std | host | notes
+-------|-----|------|-------
+`aarch64-apple-ios` | ✓[^apple] |  | ARM64 iOS
+`aarch64-fuchsia` | ✓ |  | ARM64 Fuchsia
+`aarch64-linux-android` | ✓ |  | ARM64 Android
+`aarch64-pc-windows-msvc` | ✓ |  | ARM64 Windows MSVC
+`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17)
+`aarch64-unknown-linux-musl` | ✓ |  | ARM64 Linux with MUSL
+`aarch64-unknown-none` | * |  | Bare ARM64, hardfloat
+`aarch64-unknown-none-softfloat` | * |  | Bare ARM64, softfloat
+`arm-linux-androideabi` | ✓ |  | ARMv7 Android
+`arm-unknown-linux-gnueabi` | ✓ | ✓ | ARMv6 Linux (kernel 3.2, glibc 2.17)
+`arm-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`arm-unknown-linux-musleabi` | ✓ |  | ARMv6 Linux with MUSL
+`arm-unknown-linux-musleabihf` | ✓ |  | ARMv6 Linux with MUSL, hardfloat
+`armebv7r-none-eabi` | * |  | Bare ARMv7-R, Big Endian
+`armebv7r-none-eabihf` | * |  | Bare ARMv7-R, Big Endian, hardfloat
+`armv5te-unknown-linux-gnueabi` | ✓ |  | ARMv5TE Linux (kernel 4.4, glibc 2.23)
+`armv5te-unknown-linux-musleabi` | ✓ |  | ARMv5TE Linux with MUSL
+`armv7-linux-androideabi` | ✓ |  | ARMv7a Android
+`armv7a-none-eabi` | * |  | Bare ARMv7-A
+`armv7r-none-eabi` | * |  | Bare ARMv7-R
+`armv7r-none-eabihf` | * |  | Bare ARMv7-R, hardfloat
+`armv7-unknown-linux-gnueabi` | ✓ |   | ARMv7 Linux (kernel 4.15, glibc 2.27)
+`armv7-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`armv7-unknown-linux-musleabi` | ✓ |   | ARMv7 Linux, MUSL
+`armv7-unknown-linux-musleabihf` | ✓ |  | ARMv7 Linux with MUSL
+`asmjs-unknown-emscripten` | ✓ |  | asm.js via Emscripten
+`i586-pc-windows-msvc` | ✓ |  | 32-bit Windows w/o SSE
+`i586-unknown-linux-gnu` | ✓ |  | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
+`i586-unknown-linux-musl` | ✓ |  | 32-bit Linux w/o SSE, MUSL
+`i686-linux-android` | ✓ |  | 32-bit x86 Android
+`i686-unknown-freebsd` | ✓ | ✓ | 32-bit FreeBSD
+`i686-unknown-linux-musl` | ✓ |  | 32-bit Linux with MUSL
+`mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
+`mips-unknown-linux-musl` | ✓ |  | MIPS Linux with MUSL
+`mips64-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mips64-unknown-linux-muslabi64` | ✓ |  | MIPS64 Linux, n64 ABI, MUSL
+`mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mips64el-unknown-linux-muslabi64` | ✓ |  | MIPS64 (LE) Linux, n64 ABI, MUSL
+`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
+`mipsel-unknown-linux-musl` | ✓ |  | MIPS (LE) Linux with MUSL
+`nvptx64-nvidia-cuda` | ✓ |  | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+`powerpc-unknown-linux-gnu` | ✓ | ✓ | PowerPC Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64-unknown-linux-gnu` | ✓ | ✓ | PPC64 Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64le-unknown-linux-gnu` | ✓ | ✓ | PPC64LE Linux (kernel 3.10, glibc 2.17)
+`riscv32i-unknown-none-elf` | * |  | Bare RISC-V (RV32I ISA)
+`riscv32imac-unknown-none-elf` | * |  | Bare RISC-V (RV32IMAC ISA)
+`riscv32imc-unknown-none-elf` | * |  | Bare RISC-V (RV32IMC ISA)
+`riscv64gc-unknown-linux-gnu` | ✓ | ✓ | RISC-V Linux (kernel 4.20, glibc 2.29)
+`riscv64gc-unknown-none-elf` | * |  | Bare RISC-V (RV64IMAFDC ISA)
+`riscv64imac-unknown-none-elf` | * |  | Bare RISC-V (RV64IMAC ISA)
+`s390x-unknown-linux-gnu` | ✓ | ✓ | S390x Linux (kernel 2.6.32, glibc 2.11)
+`sparc64-unknown-linux-gnu` | ✓ |  | SPARC Linux (kernel 4.4, glibc 2.23)
+`sparcv9-sun-solaris` | ✓ |  | SPARC Solaris 10/11, illumos
+`thumbv6m-none-eabi` | * |  | Bare Cortex-M0, M0+, M1
+`thumbv7em-none-eabi` | * |  | Bare Cortex-M4, M7
+`thumbv7em-none-eabihf` | * |  | Bare Cortex-M4F, M7F, FPU, hardfloat
+`thumbv7m-none-eabi` | * |  | Bare Cortex-M3
+`thumbv7neon-linux-androideabi` | ✓ |  | Thumb2-mode ARMv7a Android with NEON
+`thumbv7neon-unknown-linux-gnueabihf` | ✓ |  | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
+`thumbv8m.base-none-eabi` | * |  | ARMv8-M Baseline
+`thumbv8m.main-none-eabi` | * |  | ARMv8-M Mainline
+`thumbv8m.main-none-eabihf` | * |  | ARMv8-M Baseline, hardfloat
+`wasm32-unknown-emscripten` | ✓ |  | WebAssembly via Emscripten
+`wasm32-unknown-unknown` | ✓ |  | WebAssembly
+`wasm32-wasi` | ✓ |  | WebAssembly with WASI
+`x86_64-apple-ios` | ✓[^apple] |  | 64-bit x86 iOS
+`x86_64-fortanix-unknown-sgx` | ✓ |  | [Fortanix ABI] for 64-bit Intel SGX
+`x86_64-fuchsia` | ✓ |  | 64-bit Fuchsia
+`x86_64-linux-android` | ✓ |  | 64-bit x86 Android
+`x86_64-rumprun-netbsd` | ✓ |  | 64-bit NetBSD Rump Kernel
+`x86_64-sun-solaris` | ✓ |  | 64-bit Solaris 10/11, illumos
+`x86_64-unknown-cloudabi` | ✓ |  | 64-bit CloudABI
+`x86_64-unknown-freebsd` | ✓ | ✓ | 64-bit FreeBSD
+`x86_64-unknown-illumos` | ✓ | ✓ | illumos
+`x86_64-unknown-linux-gnux32` | ✓ |  | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
+`x86_64-unknown-linux-musl` | ✓ | ✓ | 64-bit Linux with MUSL
+`x86_64-unknown-netbsd` | ✓ | ✓ | NetBSD/amd64
+`x86_64-unknown-redox` | ✓ |  | Redox OS
+
+[Fortanix ABI]: https://edp.fortanix.com/
+
+## Tier 3
+
+Tier 3 platforms are those which the Rust codebase has support for, but which
+are not built or tested automatically, and may not work. Official builds are
+not available.
+
+target | std | host | notes
+-------|-----|------|-------
+`aarch64-apple-darwin` | ? |  | ARM64 macOS
+`aarch64-apple-tvos` | *[^apple] |  | ARM64 tvOS
+`aarch64-unknown-cloudabi` | ✓ |  | ARM64 CloudABI
+`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
+`aarch64-unknown-hermit` | ? |  |
+`aarch64-unknown-netbsd` | ? |  |
+`aarch64-unknown-openbsd` | ✓ | ✓ | ARM64 OpenBSD
+`aarch64-unknown-redox` | ? |  | ARM64 Redox OS
+`aarch64-uwp-windows-msvc` | ? |  |
+`aarch64-wrs-vxworks` | ? |  |
+`armv4t-unknown-linux-gnueabi` | ? |  |
+`armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
+`armv6-unknown-netbsd-eabihf` | ? |  |
+`armv7-apple-ios` | ✓[^apple] |  | ARMv7 iOS, Cortex-a8
+`armv7-unknown-cloudabi-eabihf` | ✓ |  | ARMv7 CloudABI, hardfloat
+`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
+`armv7-unknown-netbsd-eabihf` | ? |  |
+`armv7-wrs-vxworks-eabihf` | ? |  |
+`armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
+`armv7s-apple-ios` | ✓[^apple] |  |
+`avr-unknown-unknown` | ? |  | AVR
+`hexagon-unknown-linux-musl` | ? |  |
+`i386-apple-ios` | ✓[^apple] |  | 32-bit x86 iOS
+`i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+)
+`i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
+`i686-unknown-cloudabi` | ✓ |  | 32-bit CloudABI
+`i686-unknown-uefi` | ? |  | 32-bit UEFI
+`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
+`i686-unknown-netbsd` | ✓ |  | NetBSD/i386 with SSE2
+`i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD
+`i686-uwp-windows-gnu` | ? |  |
+`i686-uwp-windows-msvc` | ? |  |
+`i686-wrs-vxworks` | ? |  |
+`mips-unknown-linux-uclibc` | ✓ |  | MIPS Linux with uClibc
+`mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
+`mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
+`mipsisa32r6-unknown-linux-gnu` | ? |  |
+`mipsisa32r6el-unknown-linux-gnu` | ? |  |
+`mipsisa64r6-unknown-linux-gnuabi64` | ? |  |
+`mipsisa64r6el-unknown-linux-gnuabi64` | ? |  |
+`msp430-none-elf` | * |  | 16-bit MSP430 microcontrollers
+`powerpc-unknown-linux-gnuspe` | ✓ |  | PowerPC SPE Linux
+`powerpc-unknown-linux-musl` | ? |  |
+`powerpc-unknown-netbsd` | ? |  |
+`powerpc-wrs-vxworks` | ? |  |
+`powerpc-wrs-vxworks-spe` | ? |  |
+`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
+`powerpc64-unknown-linux-musl` | ? |  |
+`powerpc64-wrs-vxworks` | ? |  |
+`powerpc64le-unknown-linux-musl` | ? |  |
+`sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
+`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
+`sparc64-unknown-openbsd` | ? |  |
+`thumbv7a-pc-windows-msvc` | ? |  |
+`thumbv7a-uwp-windows-msvc` | ✓ |  |
+`thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7a Linux with NEON, MUSL
+`thumbv4t-none-eabi` | * |  | ARMv4T T32
+`x86_64-apple-ios-macabi` | ✓[^apple] |  | Apple Catalyst
+`x86_64-apple-tvos` | *[^apple] | | x86 64-bit tvOS
+`x86_64-linux-kernel` | ? |  | Linux kernel modules
+`x86_64-pc-solaris` | ? |  |
+`x86_64-pc-windows-msvc` | ✓ |  | 64-bit Windows XP support
+`x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
+`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
+`x86_64-unknown-hermit` | ? |  |
+`x86_64-unknown-hermit-kernel` | ? |  | HermitCore kernel
+`x86_64-unknown-l4re-uclibc` | ? |  |
+`x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
+`x86_64-unknown-uefi` | ? |  |
+`x86_64-uwp-windows-gnu` | ✓ |  |
+`x86_64-uwp-windows-msvc` | ✓ |  |
+`x86_64-wrs-vxworks` | ? |  |
+
+[runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
+[^apple]: These targets are only available on macOS.
diff --git a/src/doc/rustc/src/targets/built-in.md b/src/doc/rustc/src/targets/built-in.md
index 2e94ebe345a..c33b506cdae 100644
--- a/src/doc/rustc/src/targets/built-in.md
+++ b/src/doc/rustc/src/targets/built-in.md
@@ -2,9 +2,14 @@
 
 `rustc` ships with the ability to compile to many targets automatically, we
 call these "built-in" targets, and they generally correspond to targets that
-the team is supporting directly.
+the team is supporting directly. To see the list of built-in targets, you can
+run `rustc --print target-list`.
 
-To see the list of built-in targets, you can run `rustc --print target-list`,
-or look at [the API
-docs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/index.html#modules).
-Each module there defines a builder for a particular target.
\ No newline at end of file
+Typically, a target needs a compiled copy of the Rust standard library to
+work. If using [rustup], then check out the documentation on
+[Cross-compilation][rustup-cross] on how to download a pre-built standard
+library built by the official Rust distributions. Most targets will need a
+system linker, and possibly other things.
+
+[rustup]: https://github.com/rust-lang/rustup
+[rustup-cross]: https://github.com/rust-lang/rustup#cross-compilation
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_arena/lib.rs b/src/librustc_arena/lib.rs
index 5cf4f97fb88..5e6a0340d12 100644
--- a/src/librustc_arena/lib.rs
+++ b/src/librustc_arena/lib.rs
@@ -611,11 +611,7 @@ macro_rules! which_arena_for_type {
 
 #[macro_export]
 macro_rules! declare_arena {
-    // This macro has to take the same input as
-    // `impl_arena_allocatable_decoders` which requires a second version of
-    // each type. We ignore that type until we can fix
-    // `impl_arena_allocatable_decoders`.
-    ([], [$($a:tt $name:ident: $ty:ty, $_gen_ty:ty;)*], $tcx:lifetime) => {
+    ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
         #[derive(Default)]
         pub struct Arena<$tcx> {
             pub dropless: $crate::DroplessArena,
diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs
index 83a9de84ed8..6dff02486ff 100644
--- a/src/librustc_ast/ast.rs
+++ b/src/librustc_ast/ast.rs
@@ -35,6 +35,7 @@ use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
+use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::fmt;
 use std::iter;
@@ -52,7 +53,7 @@ mod tests;
 /// ```
 ///
 /// `'outer` is a label.
-#[derive(Clone, RustcEncodable, RustcDecodable, Copy, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic)]
 pub struct Label {
     pub ident: Ident,
 }
@@ -65,7 +66,7 @@ impl fmt::Debug for Label {
 
 /// A "Lifetime" is an annotation of the scope in which variable
 /// can be used, e.g. `'a` in `&'a i32`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Clone, Encodable, Decodable, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
     pub ident: Ident,
@@ -89,7 +90,7 @@ impl fmt::Display for Lifetime {
 /// along with a bunch of supporting information.
 ///
 /// E.g., `std::cmp::PartialEq`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Path {
     pub span: Span,
     /// The segments in the path: the things separated by `::`.
@@ -127,7 +128,7 @@ impl Path {
 /// A segment of a path: an identifier, an optional lifetime, and a set of types.
 ///
 /// E.g., `std`, `String` or `Box<T>`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct PathSegment {
     /// The identifier portion of this path segment.
     pub ident: Ident,
@@ -155,7 +156,7 @@ impl PathSegment {
 /// The arguments of a path segment.
 ///
 /// E.g., `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum GenericArgs {
     /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`.
     AngleBracketed(AngleBracketedArgs),
@@ -187,7 +188,7 @@ impl GenericArgs {
 }
 
 /// Concrete argument in the sequence of generic args.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum GenericArg {
     /// `'a` in `Foo<'a>`
     Lifetime(Lifetime),
@@ -208,7 +209,7 @@ impl GenericArg {
 }
 
 /// A path like `Foo<'a, T>`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)]
+#[derive(Clone, Encodable, Decodable, Debug, Default)]
 pub struct AngleBracketedArgs {
     /// The overall span.
     pub span: Span,
@@ -218,7 +219,7 @@ pub struct AngleBracketedArgs {
 
 /// Either an argument for a parameter e.g., `'a`, `Vec<u8>`, `0`,
 /// or a constraint on an associated item, e.g., `Item = String` or `Item: Bound`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum AngleBracketedArg {
     /// Argument for a generic parameter.
     Arg(GenericArg),
@@ -239,7 +240,7 @@ impl Into<Option<P<GenericArgs>>> for ParenthesizedArgs {
 }
 
 /// A path like `Foo(A, B) -> C`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct ParenthesizedArgs {
     /// Overall span
     pub span: Span,
@@ -268,7 +269,7 @@ pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
 /// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
 ///
 /// Negative bounds should also be handled here.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
 pub enum TraitBoundModifier {
     /// No modifiers
     None,
@@ -289,7 +290,7 @@ pub enum TraitBoundModifier {
 /// `typeck::collect::compute_bounds` matches these against
 /// the "special" built-in traits (see `middle::lang_items`) and
 /// detects `Copy`, `Send` and `Sync`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum GenericBound {
     Trait(PolyTraitRef, TraitBoundModifier),
     Outlives(Lifetime),
@@ -309,24 +310,54 @@ pub type GenericBounds = Vec<GenericBound>;
 /// Specifies the enforced ordering for generic parameters. In the future,
 /// if we wanted to relax this order, we could override `PartialEq` and
 /// `PartialOrd`, to allow the kinds to be unordered.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
+#[derive(Hash, Clone, Copy)]
 pub enum ParamKindOrd {
     Lifetime,
     Type,
-    Const,
+    // `unordered` is only `true` if `sess.has_features().const_generics`
+    // is active. Specifically, if it's only `min_const_generics`, it will still require
+    // ordering consts after types.
+    Const { unordered: bool },
+}
+
+impl Ord for ParamKindOrd {
+    fn cmp(&self, other: &Self) -> Ordering {
+        use ParamKindOrd::*;
+        let to_int = |v| match v {
+            Lifetime => 0,
+            Type | Const { unordered: true } => 1,
+            // technically both consts should be ordered equally,
+            // but only one is ever encountered at a time, so this is
+            // fine.
+            Const { unordered: false } => 2,
+        };
+
+        to_int(*self).cmp(&to_int(*other))
+    }
 }
+impl PartialOrd for ParamKindOrd {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialEq for ParamKindOrd {
+    fn eq(&self, other: &Self) -> bool {
+        self.cmp(other) == Ordering::Equal
+    }
+}
+impl Eq for ParamKindOrd {}
 
 impl fmt::Display for ParamKindOrd {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ParamKindOrd::Lifetime => "lifetime".fmt(f),
             ParamKindOrd::Type => "type".fmt(f),
-            ParamKindOrd::Const => "const".fmt(f),
+            ParamKindOrd::Const { .. } => "const".fmt(f),
         }
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum GenericParamKind {
     /// A lifetime definition (e.g., `'a: 'b + 'c + 'd`).
     Lifetime,
@@ -340,7 +371,7 @@ pub enum GenericParamKind {
     },
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct GenericParam {
     pub id: NodeId,
     pub ident: Ident,
@@ -352,7 +383,7 @@ pub struct GenericParam {
 
 /// Represents lifetime, type and const parameters attached to a declaration of
 /// a function, enum, trait, etc.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Generics {
     pub params: Vec<GenericParam>,
     pub where_clause: WhereClause,
@@ -375,7 +406,7 @@ impl Default for Generics {
 }
 
 /// A where-clause in a definition.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct WhereClause {
     /// `true` if we ate a `where` token: this can happen
     /// if we parsed no predicates (e.g. `struct Foo where {}`).
@@ -387,7 +418,7 @@ pub struct WhereClause {
 }
 
 /// A single predicate in a where-clause.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum WherePredicate {
     /// A type binding (e.g., `for<'c> Foo: Send + Clone + 'c`).
     BoundPredicate(WhereBoundPredicate),
@@ -410,7 +441,7 @@ impl WherePredicate {
 /// A type bound.
 ///
 /// E.g., `for<'c> Foo: Send + Clone + 'c`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct WhereBoundPredicate {
     pub span: Span,
     /// Any generics from a `for` binding.
@@ -424,7 +455,7 @@ pub struct WhereBoundPredicate {
 /// A lifetime predicate.
 ///
 /// E.g., `'a: 'b + 'c`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct WhereRegionPredicate {
     pub span: Span,
     pub lifetime: Lifetime,
@@ -434,7 +465,7 @@ pub struct WhereRegionPredicate {
 /// An equality predicate (unsupported).
 ///
 /// E.g., `T = int`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct WhereEqPredicate {
     pub id: NodeId,
     pub span: Span,
@@ -442,7 +473,7 @@ pub struct WhereEqPredicate {
     pub rhs_ty: P<Ty>,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Crate {
     pub module: Mod,
     pub attrs: Vec<Attribute>,
@@ -459,7 +490,7 @@ pub struct Crate {
 /// Possible values inside of compile-time attribute lists.
 ///
 /// E.g., the '..' in `#[name(..)]`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum NestedMetaItem {
     /// A full MetaItem, for recursive meta items.
     MetaItem(MetaItem),
@@ -472,7 +503,7 @@ pub enum NestedMetaItem {
 /// A spanned compile-time attribute item.
 ///
 /// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct MetaItem {
     pub path: Path,
     pub kind: MetaItemKind,
@@ -482,7 +513,7 @@ pub struct MetaItem {
 /// A compile-time attribute item.
 ///
 /// E.g., `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum MetaItemKind {
     /// Word meta item.
     ///
@@ -501,7 +532,7 @@ pub enum MetaItemKind {
 /// A block (`{ .. }`).
 ///
 /// E.g., `{ .. }` as in `fn foo() { .. }`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Block {
     /// The statements in the block.
     pub stmts: Vec<Stmt>,
@@ -514,7 +545,7 @@ pub struct Block {
 /// A match pattern.
 ///
 /// Patterns appear in match statements and some other contexts, such as `let` and `if let`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Pat {
     pub id: NodeId,
     pub kind: PatKind,
@@ -605,7 +636,7 @@ impl Pat {
 /// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
 /// are treated the same as` x: x, y: ref y, z: ref mut z`,
 /// except is_shorthand is true
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct FieldPat {
     /// The identifier for the field
     pub ident: Ident,
@@ -618,19 +649,19 @@ pub struct FieldPat {
     pub is_placeholder: bool,
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
 pub enum BindingMode {
     ByRef(Mutability),
     ByValue(Mutability),
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum RangeEnd {
     Included(RangeSyntax),
     Excluded,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum RangeSyntax {
     /// `...`
     DotDotDot,
@@ -638,7 +669,7 @@ pub enum RangeSyntax {
     DotDotEq,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum PatKind {
     /// Represents a wildcard pattern (`_`).
     Wild,
@@ -705,8 +736,8 @@ pub enum PatKind {
     MacCall(MacCall),
 }
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
-#[derive(HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum Mutability {
     Mut,
     Not,
@@ -739,7 +770,7 @@ impl Mutability {
 /// The kind of borrow in an `AddrOf` expression,
 /// e.g., `&place` or `&raw const place`.
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
-#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum BorrowKind {
     /// A normal borrow, `&$expr` or `&mut $expr`.
     /// The resulting type is either `&'a T` or `&'a mut T`
@@ -751,7 +782,7 @@ pub enum BorrowKind {
     Raw,
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
 pub enum BinOpKind {
     /// The `+` operator (addition)
     Add,
@@ -850,7 +881,7 @@ pub type BinOp = Spanned<BinOpKind>;
 /// Unary operator.
 ///
 /// Note that `&data` is not an operator, it's an `AddrOf` expression.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, Encodable, Decodable, Debug, Copy)]
 pub enum UnOp {
     /// The `*` operator for dereferencing
     Deref,
@@ -879,7 +910,7 @@ impl UnOp {
 }
 
 /// A statement
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Stmt {
     pub id: NodeId,
     pub kind: StmtKind,
@@ -913,7 +944,7 @@ impl Stmt {
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum StmtKind {
     /// A local (let) binding.
     Local(P<Local>),
@@ -929,7 +960,7 @@ pub enum StmtKind {
     MacCall(P<(MacCall, MacStmtStyle, AttrVec)>),
 }
 
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
 pub enum MacStmtStyle {
     /// The macro statement had a trailing semicolon (e.g., `foo! { ... };`
     /// `foo!(...);`, `foo![...];`).
@@ -943,7 +974,7 @@ pub enum MacStmtStyle {
 }
 
 /// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Local {
     pub id: NodeId,
     pub pat: P<Pat>,
@@ -964,7 +995,7 @@ pub struct Local {
 ///     _ => { println!("no match!") },
 /// }
 /// ```
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Arm {
     pub attrs: Vec<Attribute>,
     /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
@@ -979,7 +1010,7 @@ pub struct Arm {
 }
 
 /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Field {
     pub attrs: AttrVec,
     pub id: NodeId,
@@ -990,13 +1021,13 @@ pub struct Field {
     pub is_placeholder: bool,
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
 pub enum BlockCheckMode {
     Default,
     Unsafe(UnsafeSource),
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
 pub enum UnsafeSource {
     CompilerGenerated,
     UserProvided,
@@ -1007,14 +1038,14 @@ pub enum UnsafeSource {
 /// These are usually found nested inside types (e.g., array lengths)
 /// or expressions (e.g., repeat counts), and also used to define
 /// explicit discriminant values for enum variants.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct AnonConst {
     pub id: NodeId,
     pub value: P<Expr>,
 }
 
 /// An expression.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Expr {
     pub id: NodeId,
     pub kind: ExprKind,
@@ -1173,7 +1204,7 @@ impl Expr {
 }
 
 /// Limit types of a range (inclusive or exclusive)
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
 pub enum RangeLimits {
     /// Inclusive at the beginning, exclusive at the end
     HalfOpen,
@@ -1181,7 +1212,7 @@ pub enum RangeLimits {
     Closed,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum ExprKind {
     /// A `box x` expression.
     Box(P<Expr>),
@@ -1338,7 +1369,7 @@ pub enum ExprKind {
 ///  ^~~~~    ^
 ///  ty       position = 0
 /// ```
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct QSelf {
     pub ty: P<Ty>,
 
@@ -1350,7 +1381,7 @@ pub struct QSelf {
 }
 
 /// A capture clause used in closures and `async` blocks.
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum CaptureBy {
     /// `move |x| y + x`.
     Value,
@@ -1360,7 +1391,7 @@ pub enum CaptureBy {
 
 /// The movability of a generator / closure literal:
 /// whether a generator contains self-references, causing it to be `!Unpin`.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug, Copy)]
 #[derive(HashStable_Generic)]
 pub enum Movability {
     /// May contain self-references, `!Unpin`.
@@ -1371,7 +1402,7 @@ pub enum Movability {
 
 /// Represents a macro invocation. The `path` indicates which macro
 /// is being invoked, and the `args` are arguments passed to it.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct MacCall {
     pub path: Path,
     pub args: P<MacArgs>,
@@ -1385,7 +1416,7 @@ impl MacCall {
 }
 
 /// Arguments passed to an attribute or a function-like macro.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum MacArgs {
     /// No arguments - `#[attr]`.
     Empty,
@@ -1446,7 +1477,7 @@ impl MacArgs {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum MacDelimiter {
     Parenthesis,
     Bracket,
@@ -1473,14 +1504,14 @@ impl MacDelimiter {
 }
 
 /// Represents a macro definition.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct MacroDef {
     pub body: P<MacArgs>,
     /// `true` if macro was defined with `macro_rules`.
     pub macro_rules: bool,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, Eq, PartialEq)]
+#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
 #[derive(HashStable_Generic)]
 pub enum StrStyle {
     /// A regular string, like `"foo"`.
@@ -1492,7 +1523,7 @@ pub enum StrStyle {
 }
 
 /// An AST literal.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct Lit {
     /// The original literal token as written in source code.
     pub token: token::Lit,
@@ -1504,7 +1535,7 @@ pub struct Lit {
 }
 
 /// Same as `Lit`, but restricted to string literals.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct StrLit {
     /// The original literal token as written in source code.
     pub style: StrStyle,
@@ -1531,7 +1562,7 @@ impl StrLit {
 }
 
 /// Type of the integer literal based on provided suffix.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq)]
 #[derive(HashStable_Generic)]
 pub enum LitIntType {
     /// e.g. `42_i32`.
@@ -1543,7 +1574,7 @@ pub enum LitIntType {
 }
 
 /// Type of the float literal based on provided suffix.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq)]
 #[derive(HashStable_Generic)]
 pub enum LitFloatType {
     /// A float literal with a suffix (`1f32` or `1E10f32`).
@@ -1555,7 +1586,7 @@ pub enum LitFloatType {
 /// Literal kind.
 ///
 /// E.g., `"foo"`, `42`, `12.34`, or `bool`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)]
 pub enum LitKind {
     /// A string literal (`"foo"`).
     Str(Symbol, StrStyle),
@@ -1627,7 +1658,7 @@ impl LitKind {
 
 // N.B., If you change this, you'll probably want to change the corresponding
 // type structure in `middle/ty.rs` as well.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct MutTy {
     pub ty: P<Ty>,
     pub mutbl: Mutability,
@@ -1635,14 +1666,14 @@ pub struct MutTy {
 
 /// Represents a function's signature in a trait declaration,
 /// trait implementation, or free function.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct FnSig {
     pub header: FnHeader,
     pub decl: P<FnDecl>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
-#[derive(HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum FloatTy {
     F32,
     F64,
@@ -1671,8 +1702,8 @@ impl FloatTy {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
-#[derive(HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum IntTy {
     Isize,
     I8,
@@ -1736,8 +1767,8 @@ impl IntTy {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy, Debug)]
-#[derive(HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum UintTy {
     Usize,
     U8,
@@ -1800,7 +1831,7 @@ impl UintTy {
 
 /// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
 /// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct AssocTyConstraint {
     pub id: NodeId,
     pub ident: Ident,
@@ -1809,7 +1840,7 @@ pub struct AssocTyConstraint {
 }
 
 /// The kinds of an `AssocTyConstraint`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum AssocTyConstraintKind {
     /// E.g., `A = Bar` in `Foo<A = Bar>`.
     Equality { ty: P<Ty> },
@@ -1817,14 +1848,14 @@ pub enum AssocTyConstraintKind {
     Bound { bounds: GenericBounds },
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Ty {
     pub id: NodeId,
     pub kind: TyKind,
     pub span: Span,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct BareFnTy {
     pub unsafety: Unsafe,
     pub ext: Extern,
@@ -1833,7 +1864,7 @@ pub struct BareFnTy {
 }
 
 /// The various kinds of type recognized by the compiler.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum TyKind {
     /// A variable-length slice (`[T]`).
     Slice(P<Ty>),
@@ -1892,7 +1923,7 @@ impl TyKind {
 }
 
 /// Syntax used to declare a trait object.
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
 pub enum TraitObjectSyntax {
     Dyn,
     None,
@@ -1901,14 +1932,14 @@ pub enum TraitObjectSyntax {
 /// Inline assembly operand explicit register or register class.
 ///
 /// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum InlineAsmRegOrRegClass {
     Reg(Symbol),
     RegClass(Symbol),
 }
 
 bitflags::bitflags! {
-    #[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
+    #[derive(Encodable, Decodable, HashStable_Generic)]
     pub struct InlineAsmOptions: u8 {
         const PURE = 1 << 0;
         const NOMEM = 1 << 1;
@@ -1920,7 +1951,7 @@ bitflags::bitflags! {
     }
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum InlineAsmTemplatePiece {
     String(String),
     Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
@@ -1964,7 +1995,7 @@ impl InlineAsmTemplatePiece {
 /// Inline assembly operand.
 ///
 /// E.g., `out("eax") result` as in `asm!("mov eax, 2", out("eax") result)`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum InlineAsmOperand {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -1997,7 +2028,7 @@ pub enum InlineAsmOperand {
 /// Inline assembly.
 ///
 /// E.g., `asm!("NOP");`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct InlineAsm {
     pub template: Vec<InlineAsmTemplatePiece>,
     pub operands: Vec<(InlineAsmOperand, Span)>,
@@ -2008,7 +2039,7 @@ pub struct InlineAsm {
 /// Inline assembly dialect.
 ///
 /// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic)]
 pub enum LlvmAsmDialect {
     Att,
     Intel,
@@ -2017,7 +2048,7 @@ pub enum LlvmAsmDialect {
 /// LLVM-style inline assembly.
 ///
 /// E.g., `"={eax}"(result)` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct LlvmInlineAsmOutput {
     pub constraint: Symbol,
     pub expr: P<Expr>,
@@ -2028,7 +2059,7 @@ pub struct LlvmInlineAsmOutput {
 /// LLVM-style inline assembly.
 ///
 /// E.g., `llvm_asm!("NOP");`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct LlvmInlineAsm {
     pub asm: Symbol,
     pub asm_str_style: StrStyle,
@@ -2043,7 +2074,7 @@ pub struct LlvmInlineAsm {
 /// A parameter in a function header.
 ///
 /// E.g., `bar: usize` as in `fn foo(bar: usize)`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Param {
     pub attrs: AttrVec,
     pub ty: P<Ty>,
@@ -2056,7 +2087,7 @@ pub struct Param {
 /// Alternative representation for `Arg`s describing `self` parameter of methods.
 ///
 /// E.g., `&mut self` as in `fn foo(&mut self)`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum SelfKind {
     /// `self`, `mut self`
     Value(Mutability),
@@ -2134,7 +2165,7 @@ impl Param {
 ///
 /// Please note that it's different from `FnHeader` structure
 /// which contains metadata about function safety, asyncness, constness and ABI.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct FnDecl {
     pub inputs: Vec<Param>,
     pub output: FnRetTy,
@@ -2156,20 +2187,20 @@ impl FnDecl {
 }
 
 /// Is the trait definition an auto trait?
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum IsAuto {
     Yes,
     No,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
 pub enum Unsafe {
     Yes(Span),
     No,
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug)]
 pub enum Async {
     Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
     No,
@@ -2189,7 +2220,7 @@ impl Async {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
 pub enum Const {
     Yes(Span),
@@ -2198,13 +2229,13 @@ pub enum Const {
 
 /// Item defaultness.
 /// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum Defaultness {
     Default(Span),
     Final,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum ImplPolarity {
     /// `impl Trait for Type`
     Positive,
@@ -2221,7 +2252,7 @@ impl fmt::Debug for ImplPolarity {
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum FnRetTy {
     /// Returns type is not specified.
     ///
@@ -2244,7 +2275,7 @@ impl FnRetTy {
 /// Module declaration.
 ///
 /// E.g., `mod foo;` or `mod foo { .. }`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)]
+#[derive(Clone, Encodable, Decodable, Debug, Default)]
 pub struct Mod {
     /// A span from the first token past `{` to the last token until `}`.
     /// For `mod foo;`, the inner span ranges from the first token
@@ -2258,7 +2289,7 @@ pub struct Mod {
 /// Foreign module declaration.
 ///
 /// E.g., `extern { .. }` or `extern C { .. }`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct ForeignMod {
     pub abi: Option<StrLit>,
     pub items: Vec<P<ForeignItem>>,
@@ -2267,17 +2298,17 @@ pub struct ForeignMod {
 /// Global inline assembly.
 ///
 /// Also known as "module-level assembly" or "file-scoped assembly".
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, Encodable, Decodable, Debug, Copy)]
 pub struct GlobalAsm {
     pub asm: Symbol,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct EnumDef {
     pub variants: Vec<Variant>,
 }
 /// Enum variant.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Variant {
     /// Attributes of the variant.
     pub attrs: Vec<Attribute>,
@@ -2299,7 +2330,7 @@ pub struct Variant {
 }
 
 /// Part of `use` item to the right of its prefix.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum UseTreeKind {
     /// `use prefix` or `use prefix as rename`
     ///
@@ -2314,7 +2345,7 @@ pub enum UseTreeKind {
 
 /// A tree of paths sharing common prefixes.
 /// Used in `use` items both at top-level and inside of braces in import groups.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct UseTree {
     pub prefix: Path,
     pub kind: UseTreeKind,
@@ -2336,7 +2367,7 @@ impl UseTree {
 /// Distinguishes between `Attribute`s that decorate items and Attributes that
 /// are contained as statements within items. These two cases need to be
 /// distinguished for pretty-printing.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic)]
 pub enum AttrStyle {
     Outer,
     Inner,
@@ -2349,19 +2380,19 @@ rustc_index::newtype_index! {
     }
 }
 
-impl rustc_serialize::Encodable for AttrId {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_unit()
     }
 }
 
-impl rustc_serialize::Decodable for AttrId {
-    fn decode<D: Decoder>(d: &mut D) -> Result<AttrId, D::Error> {
+impl<D: Decoder> rustc_serialize::Decodable<D> for AttrId {
+    fn decode(d: &mut D) -> Result<AttrId, D::Error> {
         d.read_nil().map(|_| crate::attr::mk_attr_id())
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct AttrItem {
     pub path: Path,
     pub args: MacArgs,
@@ -2371,7 +2402,7 @@ pub struct AttrItem {
 pub type AttrVec = ThinVec<Attribute>;
 
 /// Metadata associated with an item.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Attribute {
     pub kind: AttrKind,
     pub id: AttrId,
@@ -2381,7 +2412,7 @@ pub struct Attribute {
     pub span: Span,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum AttrKind {
     /// A normal attribute.
     Normal(AttrItem),
@@ -2398,13 +2429,13 @@ pub enum AttrKind {
 /// that the `ref_id` is for. The `impl_id` maps to the "self type" of this impl.
 /// If this impl is an `ItemKind::Impl`, the `impl_id` is redundant (it could be the
 /// same as the impl's `NodeId`).
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct TraitRef {
     pub path: Path,
     pub ref_id: NodeId,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct PolyTraitRef {
     /// The `'a` in `<'a> Foo<&'a T>`.
     pub bound_generic_params: Vec<GenericParam>,
@@ -2425,7 +2456,7 @@ impl PolyTraitRef {
     }
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum CrateSugar {
     /// Source is `pub(crate)`.
     PubCrate,
@@ -2436,7 +2467,7 @@ pub enum CrateSugar {
 
 pub type Visibility = Spanned<VisibilityKind>;
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum VisibilityKind {
     Public,
     Crate(CrateSugar),
@@ -2453,7 +2484,7 @@ impl VisibilityKind {
 /// Field of a struct.
 ///
 /// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct StructField {
     pub attrs: Vec<Attribute>,
     pub id: NodeId,
@@ -2466,7 +2497,7 @@ pub struct StructField {
 }
 
 /// Fields and constructor ids of enum variants and structs.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum VariantData {
     /// Struct variant.
     ///
@@ -2501,7 +2532,7 @@ impl VariantData {
 }
 
 /// An item definition.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Item<K = ItemKind> {
     pub attrs: Vec<Attribute>,
     pub id: NodeId,
@@ -2538,7 +2569,7 @@ impl<K: Into<ItemKind>> Item<K> {
 }
 
 /// `extern` qualifier on a function item or function type.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum Extern {
     None,
     Implicit,
@@ -2555,7 +2586,7 @@ impl Extern {
 ///
 /// All the information between the visibility and the name of the function is
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
     pub unsafety: Unsafe,
     pub asyncness: Async,
@@ -2585,7 +2616,7 @@ impl Default for FnHeader {
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum ItemKind {
     /// An `extern crate` item, with the optional *original* crate name if the crate was renamed.
     ///
@@ -2724,7 +2755,7 @@ pub type AssocItem = Item<AssocItemKind>;
 /// In an implementation, all items must be provided.
 /// The `Option`s below denote the bodies, where `Some(_)`
 /// means "provided" and conversely `None` means "required".
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum AssocItemKind {
     /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
     /// If `def` is parsed, then the constant is provided, and otherwise required.
@@ -2772,7 +2803,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
 }
 
 /// An item in `extern` block.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum ForeignItemKind {
     /// A foreign static item (`static FOO: u8`).
     Static(P<Ty>, Mutability, Option<P<Expr>>),
diff --git a/src/librustc_ast/ast/tests.rs b/src/librustc_ast/ast/tests.rs
index 7558e9cc3a3..8ba55bf037b 100644
--- a/src/librustc_ast/ast/tests.rs
+++ b/src/librustc_ast/ast/tests.rs
@@ -3,6 +3,9 @@ use super::*;
 // Are ASTs encodable?
 #[test]
 fn check_asts_encodable() {
-    fn assert_encodable<T: rustc_serialize::Encodable>() {}
+    fn assert_encodable<
+        T: for<'a> rustc_serialize::Encodable<rustc_serialize::json::Encoder<'a>>,
+    >() {
+    }
     assert_encodable::<Crate>();
 }
diff --git a/src/librustc_ast/crate_disambiguator.rs b/src/librustc_ast/crate_disambiguator.rs
index 95d4c09dac3..bd7d8516714 100644
--- a/src/librustc_ast/crate_disambiguator.rs
+++ b/src/librustc_ast/crate_disambiguator.rs
@@ -9,7 +9,7 @@ use std::fmt;
 /// Hash value constructed out of all the `-C metadata` arguments passed to the
 /// compiler. Together with the crate-name forms a unique global identifier for
 /// the crate.
-#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
+#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Encodable, Decodable)]
 pub struct CrateDisambiguator(Fingerprint);
 
 impl CrateDisambiguator {
diff --git a/src/librustc_ast/lib.rs b/src/librustc_ast/lib.rs
index 3f876169d22..fb5ce311826 100644
--- a/src/librustc_ast/lib.rs
+++ b/src/librustc_ast/lib.rs
@@ -18,8 +18,7 @@
 #![feature(unicode_internals)]
 #![recursion_limit = "256"]
 
-// FIXME(#56935): Work around ICEs during cross-compilation.
-#[allow(unused)]
+#[macro_use]
 extern crate rustc_macros;
 
 #[macro_export]
diff --git a/src/librustc_ast/node_id.rs b/src/librustc_ast/node_id.rs
index cd562c48e91..1035e945538 100644
--- a/src/librustc_ast/node_id.rs
+++ b/src/librustc_ast/node_id.rs
@@ -1,10 +1,8 @@
-use rustc_serialize::{Decoder, Encoder};
 use rustc_span::ExpnId;
 use std::fmt;
 
 rustc_index::newtype_index! {
     pub struct NodeId {
-        ENCODABLE = custom
         DEBUG_FORMAT = "NodeId({})"
     }
 }
@@ -34,15 +32,3 @@ impl fmt::Display for NodeId {
         fmt::Display::fmt(&self.as_u32(), f)
     }
 }
-
-impl rustc_serialize::UseSpecializedEncodable for NodeId {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u32(self.as_u32())
-    }
-}
-
-impl rustc_serialize::UseSpecializedDecodable for NodeId {
-    fn default_decode<D: Decoder>(d: &mut D) -> Result<NodeId, D::Error> {
-        d.read_u32().map(NodeId::from_u32)
-    }
-}
diff --git a/src/librustc_ast/ptr.rs b/src/librustc_ast/ptr.rs
index 4597624ef88..e4a3cccb7ea 100644
--- a/src/librustc_ast/ptr.rs
+++ b/src/librustc_ast/ptr.rs
@@ -114,14 +114,14 @@ impl<T> fmt::Pointer for P<T> {
     }
 }
 
-impl<T: 'static + Decodable> Decodable for P<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<P<T>, D::Error> {
+impl<D: Decoder, T: 'static + Decodable<D>> Decodable<D> for P<T> {
+    fn decode(d: &mut D) -> Result<P<T>, D::Error> {
         Decodable::decode(d).map(P)
     }
 }
 
-impl<T: Encodable> Encodable for P<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         (**self).encode(s)
     }
 }
@@ -197,14 +197,14 @@ impl<'a, T> IntoIterator for &'a P<[T]> {
     }
 }
 
-impl<T: Encodable> Encodable for P<[T]> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<[T]> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         Encodable::encode(&**self, s)
     }
 }
 
-impl<T: Decodable> Decodable for P<[T]> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<P<[T]>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for P<[T]> {
+    fn decode(d: &mut D) -> Result<P<[T]>, D::Error> {
         Ok(P::from_vec(Decodable::decode(d)?))
     }
 }
diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs
index bcce881ed48..46c4be0a33b 100644
--- a/src/librustc_ast/token.rs
+++ b/src/librustc_ast/token.rs
@@ -17,13 +17,13 @@ use rustc_span::{self, Span, DUMMY_SP};
 use std::borrow::Cow;
 use std::{fmt, mem};
 
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum CommentKind {
     Line,
     Block,
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Hash, Debug, Copy)]
 #[derive(HashStable_Generic)]
 pub enum BinOpToken {
     Plus,
@@ -39,7 +39,7 @@ pub enum BinOpToken {
 }
 
 /// A delimiter token.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy)]
 #[derive(HashStable_Generic)]
 pub enum DelimToken {
     /// A round parenthesis (i.e., `(` or `)`).
@@ -62,7 +62,7 @@ impl DelimToken {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum LitKind {
     Bool, // AST only, must never appear in a `Token`
     Byte,
@@ -77,7 +77,7 @@ pub enum LitKind {
 }
 
 /// A literal token.
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct Lit {
     pub kind: LitKind,
     pub symbol: Symbol,
@@ -188,7 +188,7 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
             .contains(&name)
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum TokenKind {
     /* Expression-operator symbols. */
     Eq,
@@ -267,7 +267,7 @@ pub enum TokenKind {
 #[cfg(target_arch = "x86_64")]
 rustc_data_structures::static_assert_size!(TokenKind, 16);
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct Token {
     pub kind: TokenKind,
     pub span: Span,
@@ -688,7 +688,7 @@ impl PartialEq<TokenKind> for Token {
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Encodable, Decodable)]
 /// For interpolation during macro expansion.
 pub enum Nonterminal {
     NtItem(P<ast::Item>),
@@ -711,7 +711,7 @@ pub enum Nonterminal {
 #[cfg(target_arch = "x86_64")]
 rustc_data_structures::static_assert_size!(Nonterminal, 40);
 
-#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
 pub enum NonterminalKind {
     Item,
     Block,
diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs
index 9d0199078fa..151acddae84 100644
--- a/src/librustc_ast/tokenstream.rs
+++ b/src/librustc_ast/tokenstream.rs
@@ -35,7 +35,7 @@ use std::{iter, mem};
 ///
 /// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
 /// Nothing special happens to misnamed or misplaced `SubstNt`s.
-#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum TokenTree {
     /// A single token
     Token(Token),
@@ -124,7 +124,7 @@ where
 /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
 /// instead of a representation of the abstract syntax tree.
 /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat.
-#[derive(Clone, Debug, Default, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Default, Encodable, Decodable)]
 pub struct TokenStream(pub Lrc<Vec<TreeAndJoint>>);
 
 pub type TreeAndJoint = (TokenTree, IsJoint);
@@ -133,7 +133,7 @@ pub type TreeAndJoint = (TokenTree, IsJoint);
 #[cfg(target_arch = "x86_64")]
 rustc_data_structures::static_assert_size!(TokenStream, 8);
 
-#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable)]
 pub enum IsJoint {
     Joint,
     NonJoint,
@@ -408,7 +408,7 @@ impl Cursor {
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub struct DelimSpan {
     pub open: Span,
     pub close: Span,
diff --git a/src/librustc_ast/util/parser.rs b/src/librustc_ast/util/parser.rs
index e5bcc571d41..2ee94965756 100644
--- a/src/librustc_ast/util/parser.rs
+++ b/src/librustc_ast/util/parser.rs
@@ -222,7 +222,6 @@ impl AssocOp {
             Greater | // `{ 42 } > 3`
             GreaterEqual | // `{ 42 } >= 3`
             AssignOp(_) | // `{ 42 } +=`
-            LAnd | // `{ 42 } &&foo`
             As | // `{ 42 } as usize`
             // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
             // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs
index 2c3d1e97df9..b65a88cb90e 100644
--- a/src/librustc_ast/visit.rs
+++ b/src/librustc_ast/visit.rs
@@ -50,6 +50,13 @@ impl<'a> FnKind<'a> {
         }
     }
 
+    pub fn ident(&self) -> Option<&Ident> {
+        match self {
+            FnKind::Fn(_, ident, ..) => Some(ident),
+            _ => None,
+        }
+    }
+
     pub fn decl(&self) -> &'a FnDecl {
         match self {
             FnKind::Fn(_, _, sig, _, _) => &sig.decl,
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 45a026d4b53..3c2a063cf24 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -773,13 +773,13 @@ fn validate_generic_param_order<'a>(
         err.span_suggestion(
             span,
             &format!(
-                "reorder the parameters: lifetimes, then types{}",
-                if sess.features_untracked().const_generics
-                    || sess.features_untracked().min_const_generics
-                {
-                    ", then consts"
+                "reorder the parameters: lifetimes{}",
+                if sess.features_untracked().const_generics {
+                    ", then consts and types"
+                } else if sess.features_untracked().min_const_generics {
+                    ", then types, then consts"
                 } else {
-                    ""
+                    ", then types"
                 },
             ),
             ordered_params.clone(),
@@ -1156,7 +1156,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
                     GenericParamKind::Const { ref ty, kw_span: _ } => {
                         let ty = pprust::ty_to_string(ty);
-                        (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
+                        let unordered = self.session.features_untracked().const_generics;
+                        (
+                            ParamKindOrd::Const { unordered },
+                            Some(format!("const {}: {}", param.ident, ty)),
+                        )
                     }
                 };
                 (kind, Some(&*param.bounds), param.ident.span, ident)
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..3ddabcc17f8 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();
         }
@@ -63,7 +67,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
     }
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Encodable, Decodable)]
 pub enum InlineAttr {
     None,
     Hint,
@@ -71,7 +75,7 @@ pub enum InlineAttr {
     Never,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Encodable, Decodable)]
 pub enum OptimizeAttr {
     None,
     Speed,
@@ -126,7 +130,7 @@ pub fn find_unwind_attr(sess: &Session, attrs: &[Attribute]) -> Option<UnwindAtt
 ///
 /// - `#[stable]`
 /// - `#[unstable]`
-#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub struct Stability {
     pub level: StabilityLevel,
@@ -134,7 +138,7 @@ pub struct Stability {
 }
 
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
-#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub struct ConstStability {
     pub level: StabilityLevel,
@@ -146,7 +150,7 @@ pub struct ConstStability {
 }
 
 /// The available stability levels.
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
+#[derive(Encodable, Decodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub enum StabilityLevel {
     // Reason for the current stability level and the relevant rust-lang issue
@@ -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 });
@@ -620,7 +632,7 @@ pub fn eval_condition(
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Clone, HashStable_Generic)]
+#[derive(Encodable, Decodable, Clone, HashStable_Generic)]
 pub struct Deprecation {
     pub since: Option<Symbol>,
     /// The note to issue a reason.
@@ -785,7 +797,7 @@ where
     depr
 }
 
-#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
+#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)]
 pub enum ReprAttr {
     ReprInt(IntType),
     ReprC,
@@ -796,7 +808,8 @@ pub enum ReprAttr {
     ReprNoNiche,
 }
 
-#[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone, HashStable_Generic)]
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum IntType {
     SignedInt(ast::IntTy),
     UnsignedInt(ast::UintTy),
diff --git a/src/librustc_attr/lib.rs b/src/librustc_attr/lib.rs
index 5754bb48d24..149a950f7d4 100644
--- a/src/librustc_attr/lib.rs
+++ b/src/librustc_attr/lib.rs
@@ -6,8 +6,7 @@
 
 #![feature(or_patterns)]
 
-// FIXME(#56935): Work around ICEs during cross-compilation.
-#[allow(unused)]
+#[macro_use]
 extern crate rustc_macros;
 
 mod builtin;
diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs
index 55eab24b8a5..78cead02b7b 100644
--- a/src/librustc_builtin_macros/format.rs
+++ b/src/librustc_builtin_macros/format.rs
@@ -149,7 +149,7 @@ fn parse_args<'a>(
                 return Err(err);
             } else {
                 // ...after that delegate to `expect` to also include the other expected tokens.
-                return Err(p.expect(&token::Comma).err().unwrap());
+                let _ = p.expect(&token::Comma)?;
             }
         }
         first = false;
@@ -359,24 +359,18 @@ impl<'a, 'b> Context<'a, 'b> {
             // for `println!("{7:7$}", 1);`
             refs.sort();
             refs.dedup();
-            let (arg_list, mut sp) = if refs.len() == 1 {
-                let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect();
-                (
-                    format!("argument {}", refs[0]),
-                    if spans.is_empty() {
-                        MultiSpan::from_span(self.fmtsp)
-                    } else {
-                        MultiSpan::from_spans(spans)
-                    },
-                )
+            let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect();
+            let sp = if self.arg_spans.is_empty() || spans.is_empty() {
+                MultiSpan::from_span(self.fmtsp)
+            } else {
+                MultiSpan::from_spans(spans)
+            };
+            let arg_list = if refs.len() == 1 {
+                format!("argument {}", refs[0])
             } else {
-                let pos = MultiSpan::from_spans(spans.into_iter().map(|s| *s.unwrap()).collect());
                 let reg = refs.pop().unwrap();
-                (format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg,), pos)
+                format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg)
             };
-            if self.arg_spans.is_empty() {
-                sp = MultiSpan::from_span(self.fmtsp);
-            }
 
             e = self.ecx.struct_span_err(
                 sp,
@@ -1067,10 +1061,9 @@ pub fn expand_preparsed_format_args(
         let args_unused = errs_len;
 
         let mut diag = {
-            if errs_len == 1 {
-                let (sp, msg) = errs.into_iter().next().unwrap();
-                let mut diag = cx.ecx.struct_span_err(sp, msg);
-                diag.span_label(sp, msg);
+            if let [(sp, msg)] = &errs[..] {
+                let mut diag = cx.ecx.struct_span_err(*sp, *msg);
+                diag.span_label(*sp, *msg);
                 diag
             } else {
                 let mut diag = cx.ecx.struct_span_err(
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 5eadc536063..6f386c1287c 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -975,7 +975,6 @@ pub unsafe fn with_llvm_pmb(
         (llvm::CodeGenOptLevel::Default, ..) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
         }
-        (llvm::CodeGenOptLevel::Other, ..) => bug!("CodeGenOptLevel::Other selected"),
     }
 
     f(builder);
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 1d0b810165a..e3d90626e46 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 b977da733aa..5ce06a940d4 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_llvm/coverageinfo/mod.rs b/src/librustc_codegen_llvm/coverageinfo/mod.rs
index d7c98e9a624..54570920219 100644
--- a/src/librustc_codegen_llvm/coverageinfo/mod.rs
+++ b/src/librustc_codegen_llvm/coverageinfo/mod.rs
@@ -7,7 +7,7 @@ use libc::c_uint;
 use llvm::coverageinfo::CounterMappingRegion;
 use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region};
 use rustc_codegen_ssa::traits::{
-    BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
+    BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, MiscMethods, StaticMethods,
 };
 use rustc_data_structures::fx::FxHashMap;
 use rustc_llvm::RustString;
@@ -44,6 +44,16 @@ impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> {
 }
 
 impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+    /// Calls llvm::createPGOFuncNameVar() with the given function instance's mangled function name.
+    /// The LLVM API returns an llvm::GlobalVariable containing the function name, with the specific
+    /// variable name and linkage required by LLVM InstrProf source-based coverage instrumentation.
+    fn create_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value {
+        let llfn = self.cx.get_fn(instance);
+        let mangled_fn_name = CString::new(self.tcx.symbol_name(instance).name)
+            .expect("error converting function name to C string");
+        unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
+    }
+
     fn add_counter_region(
         &mut self,
         instance: Instance<'tcx>,
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 8d6b3f9ccb6..323c29e82d0 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -215,19 +215,19 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 self.call(llfn, &[], None)
             }
             sym::count_code_region => {
-                let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
-                let mangled_fn = tcx.symbol_name(caller_instance);
-                let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name));
-                let num_counters = self.const_u32(coverageinfo.num_counters);
                 use coverage::count_code_region_args::*;
+                let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
+
+                let fn_name = self.create_pgo_func_name_var(caller_instance);
                 let hash = args[FUNCTION_SOURCE_HASH].immediate();
+                let num_counters = self.const_u32(coverageinfo.num_counters);
                 let index = args[COUNTER_ID].immediate();
                 debug!(
                     "translating Rust intrinsic `count_code_region()` to LLVM intrinsic: \
-                    instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
-                    mangled_fn.name, hash, num_counters, index,
+                    instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
+                    fn_name, hash, num_counters, index,
                 );
-                self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
+                self.instrprof_increment(fn_name, hash, num_counters, index)
             }
             sym::va_start => self.va_start(args[0].immediate()),
             sym::va_end => self.va_end(args[0].immediate()),
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index eb7dc827f93..63b0aa64bd3 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -337,9 +337,6 @@ impl AtomicOrdering {
 #[derive(Copy, Clone)]
 #[repr(C)]
 pub enum SynchronizationScope {
-    // FIXME: figure out if this variant is needed at all.
-    #[allow(dead_code)]
-    Other,
     SingleThread,
     CrossThread,
 }
@@ -347,7 +344,6 @@ pub enum SynchronizationScope {
 impl SynchronizationScope {
     pub fn from_generic(sc: rustc_codegen_ssa::common::SynchronizationScope) -> Self {
         match sc {
-            rustc_codegen_ssa::common::SynchronizationScope::Other => SynchronizationScope::Other,
             rustc_codegen_ssa::common::SynchronizationScope::SingleThread => {
                 SynchronizationScope::SingleThread
             }
@@ -362,9 +358,6 @@ impl SynchronizationScope {
 #[derive(Copy, Clone)]
 #[repr(C)]
 pub enum FileType {
-    // FIXME: figure out if this variant is needed at all.
-    #[allow(dead_code)]
-    Other,
     AssemblyFile,
     ObjectFile,
 }
@@ -391,9 +384,6 @@ pub enum MetadataType {
 #[derive(Copy, Clone)]
 #[repr(C)]
 pub enum AsmDialect {
-    // FIXME: figure out if this variant is needed at all.
-    #[allow(dead_code)]
-    Other,
     Att,
     Intel,
 }
@@ -411,9 +401,6 @@ impl AsmDialect {
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
 pub enum CodeGenOptLevel {
-    // FIXME: figure out if this variant is needed at all.
-    #[allow(dead_code)]
-    Other,
     None,
     Less,
     Default,
@@ -513,9 +500,6 @@ pub enum DiagnosticLevel {
 #[derive(Copy, Clone)]
 #[repr(C)]
 pub enum ArchiveKind {
-    // FIXME: figure out if this variant is needed at all.
-    #[allow(dead_code)]
-    Other,
     K_GNU,
     K_BSD,
     K_DARWIN,
@@ -1802,6 +1786,8 @@ extern "C" {
         BufferOut: &RustString,
     );
 
+    pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &'a Value, FuncName: *const c_char)
+    -> &'a Value;
     pub fn LLVMRustCoverageComputeHash(Name: *const c_char) -> u64;
 
     #[allow(improper_ctypes)]
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index b631c10334c..f0b50459837 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -73,7 +73,8 @@ unsafe fn configure_llvm(sess: &Session) {
                 llvm_c_strs.push(s);
             }
         };
-        add("rustc", true); // fake program name
+        // Set the llvm "program name" to make usage and invalid argument messages more clear.
+        add("rustc -Cllvm-args=\"...\" with", true);
         if sess.time_llvm_passes() {
             add("-time-passes", false);
         }
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index 3cc1f4c3928..5707d3cd0ed 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -33,5 +33,6 @@ rustc_fs_util = { path = "../librustc_fs_util" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_index = { path = "../librustc_index" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_target = { path = "../librustc_target" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 6912667c391..5de7ffbcfcb 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);
@@ -778,9 +769,22 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 }
 
 fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
-    if crate_type != CrateType::Executable {
+    // On macOS the runtimes are distributed as dylibs which should be linked to
+    // both executables and dynamic shared objects. Everywhere else the runtimes
+    // are currently distributed as static liraries which should be linked to
+    // executables only.
+    let needs_runtime = match crate_type {
+        CrateType::Executable => true,
+        CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
+            sess.target.target.options.is_like_osx
+        }
+        CrateType::Rlib | CrateType::Staticlib => false,
+    };
+
+    if !needs_runtime {
         return;
     }
+
     let sanitizer = sess.opts.debugging_opts.sanitizer;
     if sanitizer.contains(SanitizerSet::ADDRESS) {
         link_sanitizer_runtime(sess, linker, "asan");
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index f9a782af24c..5100ef8ad4f 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -35,7 +35,7 @@ pub fn disable_localization(linker: &mut Command) {
 
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 pub struct LinkerInfo {
     exports: FxHashMap<CrateType, Vec<String>>,
 }
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index 7d742e7a7af..e7c789ad210 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -190,7 +190,9 @@ fn exported_symbols_provider_local(
         }
     }
 
-    if tcx.sess.opts.cg.profile_generate.enabled() {
+    if tcx.sess.opts.debugging_opts.instrument_coverage
+        || tcx.sess.opts.cg.profile_generate.enabled()
+    {
         // These are weak symbols that point to the profile version and the
         // profile name, which need to be treated as exported so LTO doesn't nix
         // them.
@@ -203,17 +205,6 @@ fn exported_symbols_provider_local(
         }));
     }
 
-    if tcx.sess.opts.debugging_opts.instrument_coverage {
-        // Similar to PGO profiling, preserve symbols used by LLVM InstrProf coverage profiling.
-        const COVERAGE_WEAK_SYMBOLS: [&str; 3] =
-            ["__llvm_profile_filename", "__llvm_coverage_mapping", "__llvm_covmap"];
-
-        symbols.extend(COVERAGE_WEAK_SYMBOLS.iter().map(|sym| {
-            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
-            (exported_symbol, SymbolExportLevel::C)
-        }));
-    }
-
     if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
         // Similar to profiling, preserve weak msan symbol during LTO.
         const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs
index 432b2f3bdc3..e04ed531bbf 100644
--- a/src/librustc_codegen_ssa/common.rs
+++ b/src/librustc_codegen_ssa/common.rs
@@ -72,9 +72,6 @@ pub enum AtomicOrdering {
 }
 
 pub enum SynchronizationScope {
-    // FIXME: figure out if this variant is needed at all.
-    #[allow(dead_code)]
-    Other,
     SingleThread,
     CrossThread,
 }
diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs
index 1e06de06108..73e33369175 100644
--- a/src/librustc_codegen_ssa/lib.rs
+++ b/src/librustc_codegen_ssa/lib.rs
@@ -17,6 +17,8 @@
 //! have to be implemented by each backends.
 
 #[macro_use]
+extern crate rustc_macros;
+#[macro_use]
 extern crate tracing;
 #[macro_use]
 extern crate rustc_middle;
@@ -74,7 +76,7 @@ impl<M> ModuleCodegen<M> {
     }
 }
 
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Encodable, Decodable)]
 pub struct CompiledModule {
     pub name: String,
     pub kind: ModuleKind,
@@ -87,7 +89,7 @@ pub struct CachedModuleCodegen {
     pub source: WorkProduct,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable)]
 pub enum ModuleKind {
     Regular,
     Metadata,
@@ -110,7 +112,7 @@ bitflags::bitflags! {
 /// identifiers (`CrateNum`) to `CrateSource`. The other fields map `CrateNum` to the crate's own
 /// additional properties, so that effectively we can retrieve each dependent crate's `CrateSource`
 /// and the corresponding properties without referencing information outside of a `CrateInfo`.
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Encodable, Decodable)]
 pub struct CrateInfo {
     pub panic_runtime: Option<CrateNum>,
     pub compiler_builtins: Option<CrateNum>,
@@ -128,7 +130,7 @@ pub struct CrateInfo {
     pub dependency_formats: Lrc<Dependencies>,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 pub struct CodegenResults {
     pub crate_name: Symbol,
     pub modules: Vec<CompiledModule>,
diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs
index d166a27b5a9..d8a530d98fa 100644
--- a/src/librustc_codegen_ssa/mir/debuginfo.rs
+++ b/src/librustc_codegen_ssa/mir/debuginfo.rs
@@ -1,6 +1,7 @@
 use crate::traits::*;
 use rustc_hir::def_id::CrateNum;
 use rustc_index::vec::IndexVec;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_session::config::DebugInfo;
@@ -216,6 +217,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             LocalRef::Operand(None) => return,
 
             LocalRef::Operand(Some(operand)) => {
+                // Don't spill operands onto the stack in naked functions.
+                // See: https://github.com/rust-lang/rust/issues/42779
+                let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id());
+                if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+                    return;
+                }
+
                 // "Spill" the value onto the stack, for debuginfo,
                 // without forcing non-debuginfo uses of the local
                 // to also load from the stack every single time.
diff --git a/src/librustc_codegen_ssa/traits/coverageinfo.rs b/src/librustc_codegen_ssa/traits/coverageinfo.rs
index 2b5878f46bc..5602599b0c2 100644
--- a/src/librustc_codegen_ssa/traits/coverageinfo.rs
+++ b/src/librustc_codegen_ssa/traits/coverageinfo.rs
@@ -7,6 +7,8 @@ pub trait CoverageInfoMethods: BackendTypes {
 }
 
 pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
+    fn create_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value;
+
     fn add_counter_region(
         &mut self,
         instance: Instance<'tcx>,
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index fda0fc5973b..00dab143fdc 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -17,6 +17,7 @@ jobserver_crate = { version = "0.1.13", package = "jobserver" }
 lazy_static = "1"
 once_cell = { version = "1", features = ["parking_lot"] }
 rustc_serialize = { path = "../librustc_serialize" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_graphviz = { path = "../librustc_graphviz" }
 cfg-if = "0.1.2"
 crossbeam-utils = { version = "0.7", features = ["nightly"] }
@@ -30,6 +31,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/fingerprint.rs b/src/librustc_data_structures/fingerprint.rs
index 282626611d5..f8d631ce01e 100644
--- a/src/librustc_data_structures/fingerprint.rs
+++ b/src/librustc_data_structures/fingerprint.rs
@@ -1,5 +1,8 @@
 use crate::stable_hasher;
-use rustc_serialize::opaque::{Decoder, EncodeResult, Encoder};
+use rustc_serialize::{
+    opaque::{self, EncodeResult},
+    Decodable, Encodable,
+};
 use std::mem;
 
 #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
@@ -49,14 +52,14 @@ impl Fingerprint {
         format!("{:x}{:x}", self.0, self.1)
     }
 
-    pub fn encode_opaque(&self, encoder: &mut Encoder) -> EncodeResult {
+    pub fn encode_opaque(&self, encoder: &mut opaque::Encoder) -> EncodeResult {
         let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) };
 
         encoder.emit_raw_bytes(&bytes);
         Ok(())
     }
 
-    pub fn decode_opaque(decoder: &mut Decoder<'_>) -> Result<Fingerprint, String> {
+    pub fn decode_opaque(decoder: &mut opaque::Decoder<'_>) -> Result<Fingerprint, String> {
         let mut bytes = [0; 16];
 
         decoder.read_raw_bytes(&mut bytes)?;
@@ -83,18 +86,45 @@ impl stable_hasher::StableHasherResult for Fingerprint {
 
 impl_stable_hash_via_hash!(Fingerprint);
 
-impl rustc_serialize::UseSpecializedEncodable for Fingerprint {}
+impl<E: rustc_serialize::Encoder> Encodable<E> for Fingerprint {
+    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+        s.encode_fingerprint(self)
+    }
+}
 
-impl rustc_serialize::UseSpecializedDecodable for Fingerprint {}
+impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint {
+    fn decode(d: &mut D) -> Result<Self, D::Error> {
+        d.decode_fingerprint()
+    }
+}
 
-impl rustc_serialize::SpecializedEncoder<Fingerprint> for Encoder {
-    fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
+pub trait FingerprintEncoder: rustc_serialize::Encoder {
+    fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), Self::Error>;
+}
+
+pub trait FingerprintDecoder: rustc_serialize::Decoder {
+    fn decode_fingerprint(&mut self) -> Result<Fingerprint, Self::Error>;
+}
+
+impl<E: rustc_serialize::Encoder> FingerprintEncoder for E {
+    default fn encode_fingerprint(&mut self, _: &Fingerprint) -> Result<(), E::Error> {
+        panic!("Cannot encode `Fingerprint` with `{}`", std::any::type_name::<E>());
+    }
+}
+
+impl FingerprintEncoder for opaque::Encoder {
+    fn encode_fingerprint(&mut self, f: &Fingerprint) -> EncodeResult {
         f.encode_opaque(self)
     }
 }
 
-impl<'a> rustc_serialize::SpecializedDecoder<Fingerprint> for Decoder<'a> {
-    fn specialized_decode(&mut self) -> Result<Fingerprint, Self::Error> {
+impl<D: rustc_serialize::Decoder> FingerprintDecoder for D {
+    default fn decode_fingerprint(&mut self) -> Result<Fingerprint, D::Error> {
+        panic!("Cannot decode `Fingerprint` with `{}`", std::any::type_name::<D>());
+    }
+}
+impl FingerprintDecoder for opaque::Decoder<'_> {
+    fn decode_fingerprint(&mut self) -> Result<Fingerprint, String> {
         Fingerprint::decode_opaque(self)
     }
 }
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 242390fbde8..1937f615e70 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -29,6 +29,8 @@
 extern crate tracing;
 #[macro_use]
 extern crate cfg_if;
+#[macro_use]
+extern crate rustc_macros;
 
 #[inline(never)]
 #[cold]
@@ -95,6 +97,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/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs
index 652268dcee8..856eb73e629 100644
--- a/src/librustc_data_structures/sorted_map.rs
+++ b/src/librustc_data_structures/sorted_map.rs
@@ -16,18 +16,7 @@ pub use index_map::SortedIndexMultiMap;
 /// stores data in a more compact way. It also supports accessing contiguous
 /// ranges of elements as a slice, and slices of already sorted elements can be
 /// inserted efficiently.
-#[derive(
-    Clone,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord,
-    Hash,
-    Default,
-    Debug,
-    RustcEncodable,
-    RustcDecodable
-)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
 pub struct SortedMap<K: Ord, V> {
     data: Vec<(K, V)>,
 }
diff --git a/src/librustc_data_structures/svh.rs b/src/librustc_data_structures/svh.rs
index 476eb9e14f9..02103de2e8d 100644
--- a/src/librustc_data_structures/svh.rs
+++ b/src/librustc_data_structures/svh.rs
@@ -48,14 +48,14 @@ impl fmt::Display for Svh {
     }
 }
 
-impl Encodable for Svh {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for Svh {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_u64(self.as_u64().to_le())
     }
 }
 
-impl Decodable for Svh {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Svh, D::Error> {
+impl<D: Decoder> Decodable<D> for Svh {
+    fn decode(d: &mut D) -> Result<Svh, D::Error> {
         d.read_u64().map(u64::from_le).map(Svh::new)
     }
 }
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_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs
index 43002178eb9..4d673fd5cf9 100644
--- a/src/librustc_data_structures/thin_vec.rs
+++ b/src/librustc_data_structures/thin_vec.rs
@@ -3,7 +3,7 @@ use crate::stable_hasher::{HashStable, StableHasher};
 /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`).
 /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
 /// which uses only a single (null) pointer.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub struct ThinVec<T>(Option<Box<Vec<T>>>);
 
 impl<T> ThinVec<T> {
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index 7d137a55033..fe60a99dde0 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -1,8 +1,6 @@
 use crate::fx::FxIndexSet;
-use crate::stable_hasher::{HashStable, StableHasher};
 use crate::sync::Lock;
 use rustc_index::bit_set::BitMatrix;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::mem;
@@ -42,10 +40,10 @@ impl<T: Eq + Hash> Default for TransitiveRelation<T> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)]
 struct Index(usize);
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug)]
 struct Edge {
     source: Index,
     target: Index,
@@ -402,66 +400,3 @@ fn pare_down(candidates: &mut Vec<usize>, closure: &BitMatrix<usize, usize>) {
         candidates.truncate(j - dead);
     }
 }
-
-impl<T> Encodable for TransitiveRelation<T>
-where
-    T: Clone + Encodable + Debug + Eq + Hash + Clone,
-{
-    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct("TransitiveRelation", 2, |s| {
-            s.emit_struct_field("elements", 0, |s| self.elements.encode(s))?;
-            s.emit_struct_field("edges", 1, |s| self.edges.encode(s))?;
-            Ok(())
-        })
-    }
-}
-
-impl<T> Decodable for TransitiveRelation<T>
-where
-    T: Clone + Decodable + Debug + Eq + Hash + Clone,
-{
-    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
-        d.read_struct("TransitiveRelation", 2, |d| {
-            Ok(TransitiveRelation {
-                elements: d.read_struct_field("elements", 0, |d| Decodable::decode(d))?,
-                edges: d.read_struct_field("edges", 1, |d| Decodable::decode(d))?,
-                closure: Lock::new(None),
-            })
-        })
-    }
-}
-
-impl<CTX, T> HashStable<CTX> for TransitiveRelation<T>
-where
-    T: HashStable<CTX> + Eq + Debug + Clone + Hash,
-{
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        // We are assuming here that the relation graph has been built in a
-        // deterministic way and we can just hash it the way it is.
-        let TransitiveRelation {
-            ref elements,
-            ref edges,
-            // "closure" is just a copy of the data above
-            closure: _,
-        } = *self;
-
-        elements.hash_stable(hcx, hasher);
-        edges.hash_stable(hcx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for Edge {
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        let Edge { ref source, ref target } = *self;
-
-        source.hash_stable(hcx, hasher);
-        target.hash_stable(hcx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for Index {
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        let Index(idx) = *self;
-        idx.hash_stable(hcx, hasher);
-    }
-}
diff --git a/src/librustc_error_codes/error_codes/E0477.md b/src/librustc_error_codes/error_codes/E0477.md
index 794456451ef..9cfefb1de63 100644
--- a/src/librustc_error_codes/error_codes/E0477.md
+++ b/src/librustc_error_codes/error_codes/E0477.md
@@ -37,8 +37,7 @@ fn i_want_static_closure<F>(a: F)
 
 fn print_string(s: Mutex<MyString<'static>>) {
 
-    i_want_static_closure(move || {     // error: this closure has lifetime 'a
-                                        //        rather than 'static
+    i_want_static_closure(move || {     // ok!
         println!("{}", s.lock().unwrap().data);
     });
 }
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_error_codes/error_codes/E0752.md b/src/librustc_error_codes/error_codes/E0752.md
index 86945f83b55..9736da80c2b 100644
--- a/src/librustc_error_codes/error_codes/E0752.md
+++ b/src/librustc_error_codes/error_codes/E0752.md
@@ -1,11 +1,19 @@
-`fn main()` or the specified start function is not allowed to be
-async. You might be seeing this error because your async runtime
-library is not set up correctly.
+The entry point of the program was marked as `async`.
 
 Erroneous code example:
 
 ```compile_fail,E0752
-async fn main() -> Result<i32, ()> {
-    Ok(1)
+async fn main() -> Result<(), ()> { // error!
+    Ok(())
+}
+```
+
+`fn main()` or the specified start function is not allowed to be `async`. Not
+having a correct async runtime library setup may cause this error. To fix it,
+declare the entry point without `async`:
+
+```
+fn main() -> Result<(), ()> { // ok!
+    Ok(())
 }
 ```
diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml
index d0f04c3fe76..c17d61dae9f 100644
--- a/src/librustc_errors/Cargo.toml
+++ b/src/librustc_errors/Cargo.toml
@@ -13,6 +13,7 @@ doctest = false
 log = { package = "tracing", version = "0.1" }
 rustc_serialize = { path = "../librustc_serialize" }
 rustc_span = { path = "../librustc_span" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 unicode-width = "0.1.4"
 atty = "0.2"
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index acaa26c6ad2..cd4b5d56f36 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -9,7 +9,7 @@ use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
 #[must_use]
-#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub struct Diagnostic {
     pub level: Level,
     pub message: Vec<(String, Style)>,
@@ -24,14 +24,14 @@ pub struct Diagnostic {
     pub sort_span: Span,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
 pub enum DiagnosticId {
     Error(String),
     Lint(String),
 }
 
 /// For example a note attached to an error.
-#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub struct SubDiagnostic {
     pub level: Level,
     pub message: Vec<(String, Style)>,
diff --git a/src/librustc_errors/json.rs b/src/librustc_errors/json.rs
index 24186198fd2..750d36d3d89 100644
--- a/src/librustc_errors/json.rs
+++ b/src/librustc_errors/json.rs
@@ -145,7 +145,7 @@ impl Emitter for JsonEmitter {
 
 // The following data types are provided just for serialisation.
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct Diagnostic {
     /// The primary error message.
     message: String,
@@ -159,7 +159,7 @@ struct Diagnostic {
     rendered: Option<String>,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct DiagnosticSpan {
     file_name: String,
     byte_start: u32,
@@ -186,7 +186,7 @@ struct DiagnosticSpan {
     expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct DiagnosticSpanLine {
     text: String,
 
@@ -196,7 +196,7 @@ struct DiagnosticSpanLine {
     highlight_end: usize,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct DiagnosticSpanMacroExpansion {
     /// span where macro was applied to generate this code; note that
     /// this may itself derive from a macro (if
@@ -210,7 +210,7 @@ struct DiagnosticSpanMacroExpansion {
     def_site_span: DiagnosticSpan,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct DiagnosticCode {
     /// The code itself.
     code: String,
@@ -218,7 +218,7 @@ struct DiagnosticCode {
     explanation: Option<&'static str>,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct ArtifactNotification<'a> {
     /// The path of the artifact.
     artifact: &'a Path,
diff --git a/src/librustc_errors/json/tests.rs b/src/librustc_errors/json/tests.rs
index dcfcdbc63f2..e69e868c8ed 100644
--- a/src/librustc_errors/json/tests.rs
+++ b/src/librustc_errors/json/tests.rs
@@ -10,12 +10,12 @@ use rustc_span::{BytePos, Span};
 
 use std::str;
 
-#[derive(RustcDecodable, Debug, PartialEq, Eq)]
+#[derive(Decodable, Debug, PartialEq, Eq)]
 struct TestData {
     spans: Vec<SpanTestData>,
 }
 
-#[derive(RustcDecodable, Debug, PartialEq, Eq)]
+#[derive(Decodable, Debug, PartialEq, Eq)]
 struct SpanTestData {
     pub byte_start: u32,
     pub byte_end: u32,
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 73d71063b23..98e9972530e 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -6,6 +6,9 @@
 #![feature(crate_visibility_modifier)]
 #![feature(nll)]
 
+#[macro_use]
+extern crate rustc_macros;
+
 pub use emitter::ColorConfig;
 
 use log::debug;
@@ -50,7 +53,7 @@ rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
 /// to determine whether it should be automatically applied or if the user should be consulted
 /// before applying the suggestion.
-#[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub enum Applicability {
     /// The suggestion is definitely what the user intended. This suggestion should be
     /// automatically applied.
@@ -69,7 +72,7 @@ pub enum Applicability {
     Unspecified,
 }
 
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
 pub enum SuggestionStyle {
     /// Hide the suggested code when displaying this suggestion inline.
     HideCodeInline,
@@ -94,7 +97,7 @@ impl SuggestionStyle {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub struct CodeSuggestion {
     /// Each substitute can have multiple variants due to multiple
     /// applicable suggestions
@@ -129,13 +132,13 @@ pub struct CodeSuggestion {
     pub applicability: Applicability,
 }
 
-#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 /// See the docs on `CodeSuggestion::substitutions`
 pub struct Substitution {
     pub parts: Vec<SubstitutionPart>,
 }
 
-#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub struct SubstitutionPart {
     pub span: Span,
     pub snippet: String,
@@ -943,7 +946,7 @@ impl HandlerInner {
     }
 }
 
-#[derive(Copy, PartialEq, Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)]
 pub enum Level {
     Bug,
     Fatal,
@@ -1012,7 +1015,7 @@ macro_rules! pluralize {
 
 // Useful type to use with `Result<>` indicate that an error has already
 // been reported to the user, so no need to continue checking.
-#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable, Hash, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq)]
 pub struct ErrorReported;
 
 rustc_data_structures::impl_stable_hash_via_hash!(ErrorReported);
diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs
index 0660590a725..160bf577799 100644
--- a/src/librustc_errors/snippet.rs
+++ b/src/librustc_errors/snippet.rs
@@ -173,7 +173,7 @@ pub struct StyledString {
     pub style: Style,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub enum Style {
     MainHeaderMsg,
     HeaderMsg,
diff --git a/src/librustc_expand/Cargo.toml b/src/librustc_expand/Cargo.toml
index bdf039c36ab..fbdb65b5587 100644
--- a/src/librustc_expand/Cargo.toml
+++ b/src/librustc_expand/Cargo.toml
@@ -20,6 +20,7 @@ rustc_attr = { path = "../librustc_attr" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_parse = { path = "../librustc_parse" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs
index 1e3ab2c5ec2..7f631cb71af 100644
--- a/src/librustc_expand/lib.rs
+++ b/src/librustc_expand/lib.rs
@@ -8,6 +8,9 @@
 #![feature(proc_macro_span)]
 #![feature(try_blocks)]
 
+#[macro_use]
+extern crate rustc_macros;
+
 extern crate proc_macro as pm;
 
 mod placeholders;
diff --git a/src/librustc_expand/mbe.rs b/src/librustc_expand/mbe.rs
index 6f2daaa81c0..9920e0650a7 100644
--- a/src/librustc_expand/mbe.rs
+++ b/src/librustc_expand/mbe.rs
@@ -19,7 +19,7 @@ use rustc_data_structures::sync::Lrc;
 
 /// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
 /// that the delimiter itself might be `NoDelim`.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
 struct Delimited {
     delim: token::DelimToken,
     tts: Vec<TokenTree>,
@@ -37,7 +37,7 @@ impl Delimited {
     }
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
 struct SequenceRepetition {
     /// The sequence of token trees
     tts: Vec<TokenTree>,
@@ -49,7 +49,7 @@ struct SequenceRepetition {
     num_captures: usize,
 }
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
 struct KleeneToken {
     span: Span,
     op: KleeneOp,
@@ -63,7 +63,7 @@ impl KleeneToken {
 
 /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
 /// for token sequences.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
 enum KleeneOp {
     /// Kleene star (`*`) for zero or more repetitions
     ZeroOrMore,
@@ -75,7 +75,7 @@ enum KleeneOp {
 
 /// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
 /// are "first-class" token trees. Useful for parsing macros.
-#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
 enum TokenTree {
     Token(Token),
     Delimited(DelimSpan, Lrc<Delimited>),
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_hir/arena.rs b/src/librustc_hir/arena.rs
index f439db71531..6ba39666607 100644
--- a/src/librustc_hir/arena.rs
+++ b/src/librustc_hir/arena.rs
@@ -12,41 +12,41 @@ macro_rules! arena_types {
     ($macro:path, $args:tt, $tcx:lifetime) => (
         $macro!($args, [
             // HIR types
-            [few] hir_krate: rustc_hir::Crate<$tcx>, rustc_hir::Crate<'_x>;
-            [] arm: rustc_hir::Arm<$tcx>, rustc_hir::Arm<'_x>;
-            [] asm_operand: rustc_hir::InlineAsmOperand<$tcx>, rustc_hir::InlineAsmOperand<'_x>;
-            [] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, rustc_ast::ast::InlineAsmTemplatePiece;
-            [] attribute: rustc_ast::ast::Attribute, rustc_ast::ast::Attribute;
-            [] block: rustc_hir::Block<$tcx>, rustc_hir::Block<'_x>;
-            [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>, rustc_hir::BareFnTy<'_x>;
-            [few] global_asm: rustc_hir::GlobalAsm, rustc_hir::GlobalAsm;
-            [] generic_arg: rustc_hir::GenericArg<$tcx>, rustc_hir::GenericArg<'_x>;
-            [] generic_args: rustc_hir::GenericArgs<$tcx>, rustc_hir::GenericArgs<'_x>;
-            [] generic_bound: rustc_hir::GenericBound<$tcx>, rustc_hir::GenericBound<'_x>;
-            [] generic_param: rustc_hir::GenericParam<$tcx>, rustc_hir::GenericParam<'_x>;
-            [] expr: rustc_hir::Expr<$tcx>, rustc_hir::Expr<'_x>;
-            [] field: rustc_hir::Field<$tcx>, rustc_hir::Field<'_x>;
-            [] field_pat: rustc_hir::FieldPat<$tcx>, rustc_hir::FieldPat<'_x>;
-            [] fn_decl: rustc_hir::FnDecl<$tcx>, rustc_hir::FnDecl<'_x>;
-            [] foreign_item: rustc_hir::ForeignItem<$tcx>, rustc_hir::ForeignItem<'_x>;
-            [] impl_item_ref: rustc_hir::ImplItemRef<$tcx>, rustc_hir::ImplItemRef<'_x>;
-            [few] inline_asm: rustc_hir::InlineAsm<$tcx>, rustc_hir::InlineAsm<'_x>;
-            [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, rustc_hir::LlvmInlineAsm<'_x>;
-            [] local: rustc_hir::Local<$tcx>, rustc_hir::Local<'_x>;
-            [few] macro_def: rustc_hir::MacroDef<$tcx>, rustc_hir::MacroDef<'_x>;
-            [] param: rustc_hir::Param<$tcx>, rustc_hir::Param<'_x>;
-            [] pat: rustc_hir::Pat<$tcx>, rustc_hir::Pat<'_x>;
-            [] path: rustc_hir::Path<$tcx>, rustc_hir::Path<'_x>;
-            [] path_segment: rustc_hir::PathSegment<$tcx>, rustc_hir::PathSegment<'_x>;
-            [] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>, rustc_hir::PolyTraitRef<'_x>;
-            [] qpath: rustc_hir::QPath<$tcx>, rustc_hir::QPath<'_x>;
-            [] stmt: rustc_hir::Stmt<$tcx>, rustc_hir::Stmt<'_x>;
-            [] struct_field: rustc_hir::StructField<$tcx>, rustc_hir::StructField<'_x>;
-            [] trait_item_ref: rustc_hir::TraitItemRef, rustc_hir::TraitItemRef;
-            [] ty: rustc_hir::Ty<$tcx>, rustc_hir::Ty<'_x>;
-            [] type_binding: rustc_hir::TypeBinding<$tcx>, rustc_hir::TypeBinding<'_x>;
-            [] variant: rustc_hir::Variant<$tcx>, rustc_hir::Variant<'_x>;
-            [] where_predicate: rustc_hir::WherePredicate<$tcx>, rustc_hir::WherePredicate<'_x>;
+            [few] hir_krate: rustc_hir::Crate<$tcx>,
+            [] arm: rustc_hir::Arm<$tcx>,
+            [] asm_operand: rustc_hir::InlineAsmOperand<$tcx>,
+            [] asm_template: rustc_ast::ast::InlineAsmTemplatePiece,
+            [] attribute: rustc_ast::ast::Attribute,
+            [] block: rustc_hir::Block<$tcx>,
+            [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>,
+            [few] global_asm: rustc_hir::GlobalAsm,
+            [] generic_arg: rustc_hir::GenericArg<$tcx>,
+            [] generic_args: rustc_hir::GenericArgs<$tcx>,
+            [] generic_bound: rustc_hir::GenericBound<$tcx>,
+            [] generic_param: rustc_hir::GenericParam<$tcx>,
+            [] expr: rustc_hir::Expr<$tcx>,
+            [] field: rustc_hir::Field<$tcx>,
+            [] field_pat: rustc_hir::FieldPat<$tcx>,
+            [] fn_decl: rustc_hir::FnDecl<$tcx>,
+            [] foreign_item: rustc_hir::ForeignItem<$tcx>,
+            [] impl_item_ref: rustc_hir::ImplItemRef<$tcx>,
+            [few] inline_asm: rustc_hir::InlineAsm<$tcx>,
+            [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
+            [] local: rustc_hir::Local<$tcx>,
+            [few] macro_def: rustc_hir::MacroDef<$tcx>,
+            [] param: rustc_hir::Param<$tcx>,
+            [] pat: rustc_hir::Pat<$tcx>,
+            [] path: rustc_hir::Path<$tcx>,
+            [] path_segment: rustc_hir::PathSegment<$tcx>,
+            [] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>,
+            [] qpath: rustc_hir::QPath<$tcx>,
+            [] stmt: rustc_hir::Stmt<$tcx>,
+            [] struct_field: rustc_hir::StructField<$tcx>,
+            [] trait_item_ref: rustc_hir::TraitItemRef,
+            [] ty: rustc_hir::Ty<$tcx>,
+            [] type_binding: rustc_hir::TypeBinding<$tcx>,
+            [] variant: rustc_hir::Variant<$tcx>,
+            [] where_predicate: rustc_hir::WherePredicate<$tcx>,
         ], $tcx);
     )
 }
diff --git a/src/librustc_hir/def.rs b/src/librustc_hir/def.rs
index 618f3e99c3f..c4877be3f64 100644
--- a/src/librustc_hir/def.rs
+++ b/src/librustc_hir/def.rs
@@ -9,7 +9,7 @@ use rustc_span::hygiene::MacroKind;
 use std::fmt::Debug;
 
 /// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct.
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum CtorOf {
     /// This `DefKind::Ctor` is a synthesized constructor of a tuple or unit struct.
@@ -18,7 +18,7 @@ pub enum CtorOf {
     Variant,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum CtorKind {
     /// Constructor function automatically created by a tuple struct/variant.
@@ -29,7 +29,7 @@ pub enum CtorKind {
     Fictive,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum NonMacroAttrKind {
     /// Single-segment attribute defined by the language (`#[inline]`)
@@ -42,7 +42,7 @@ pub enum NonMacroAttrKind {
     Registered,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum DefKind {
     // Type namespace
@@ -191,7 +191,7 @@ impl DefKind {
 }
 
 /// The resolution of a path or export.
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum Res<Id = hir::HirId> {
     Def(DefKind, DefId),
diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs
index 79b70682739..5604e3a8dca 100644
--- a/src/librustc_hir/definitions.rs
+++ b/src/librustc_hir/definitions.rs
@@ -23,7 +23,7 @@ use std::hash::Hash;
 /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
 /// stores the `DefIndex` of its parent.
 /// There is one `DefPathTable` for each crate.
-#[derive(Clone, Default, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Default, Decodable, Encodable)]
 pub struct DefPathTable {
     index_to_key: IndexVec<DefIndex, DefKey>,
     def_path_hashes: IndexVec<DefIndex, DefPathHash>,
@@ -92,7 +92,7 @@ pub struct Definitions {
 /// A unique identifier that we can use to lookup a definition
 /// precisely. It combines the index of the definition's parent (if
 /// any) with a `DisambiguatedDefPathData`.
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
 pub struct DefKey {
     /// The parent path.
     pub parent: Option<DefIndex>,
@@ -143,13 +143,13 @@ impl DefKey {
 /// between them. This introduces some artificial ordering dependency
 /// but means that if you have, e.g., two impls for the same type in
 /// the same module, they do get distinct `DefId`s.
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
 pub struct DisambiguatedDefPathData {
     pub data: DefPathData,
     pub disambiguator: u32,
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Encodable, Decodable)]
 pub struct DefPath {
     /// The path leading from the crate root to the item.
     pub data: Vec<DisambiguatedDefPathData>,
@@ -244,7 +244,7 @@ impl DefPath {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
 pub enum DefPathData {
     // Root: these should only be used for the root nodes, because
     // they are treated specially by the `def_path` function.
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 6474dc318d3..928235adac3 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -23,7 +23,7 @@ use smallvec::SmallVec;
 use std::collections::{BTreeMap, BTreeSet};
 use std::fmt;
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, HashStable_Generic)]
 pub struct Lifetime {
     pub hir_id: HirId,
     pub span: Span,
@@ -37,7 +37,7 @@ pub struct Lifetime {
     pub name: LifetimeName,
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+#[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)]
 #[derive(HashStable_Generic)]
 pub enum ParamName {
     /// Some user-given name like `T` or `'x`.
@@ -83,7 +83,7 @@ impl ParamName {
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+#[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)]
 #[derive(HashStable_Generic)]
 pub enum LifetimeName {
     /// User-given names or fresh (synthetic) names.
@@ -182,7 +182,7 @@ impl Lifetime {
 /// A `Path` is essentially Rust's notion of a name; for instance,
 /// `std::cmp::PartialEq`. It's represented as a sequence of identifiers,
 /// along with a bunch of supporting information.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Path<'hir> {
     pub span: Span,
     /// The resolution for the path.
@@ -199,7 +199,7 @@ impl Path<'_> {
 
 /// A segment of a path: an identifier, an optional lifetime, and a set of
 /// types.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct PathSegment<'hir> {
     /// The identifier portion of this path segment.
     #[stable_hasher(project(name))]
@@ -242,13 +242,13 @@ impl<'hir> PathSegment<'hir> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub struct ConstArg {
     pub value: AnonConst,
     pub span: Span,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum GenericArg<'hir> {
     Lifetime(Lifetime),
     Type(Ty<'hir>),
@@ -288,7 +288,7 @@ impl GenericArg<'_> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct GenericArgs<'hir> {
     /// The generic arguments for this path segment.
     pub args: &'hir [GenericArg<'hir>],
@@ -348,7 +348,7 @@ impl GenericArgs<'_> {
 
 /// A modifier on a bound, currently this is only used for `?Sized`, where the
 /// modifier is `Maybe`. Negative bounds should also be handled here.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum TraitBoundModifier {
     None,
@@ -360,7 +360,7 @@ pub enum TraitBoundModifier {
 /// `typeck::collect::compute_bounds` matches these against
 /// the "special" built-in traits (see `middle::lang_items`) and
 /// detects `Copy`, `Send` and `Sync`.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
     Outlives(Lifetime),
@@ -384,7 +384,7 @@ impl GenericBound<'_> {
 
 pub type GenericBounds<'hir> = &'hir [GenericBound<'hir>];
 
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
 pub enum LifetimeParamKind {
     // Indicates that the lifetime definition was explicitly declared (e.g., in
     // `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`).
@@ -403,7 +403,7 @@ pub enum LifetimeParamKind {
     Error,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum GenericParamKind<'hir> {
     /// A lifetime definition (e.g., `'a: 'b + 'c + 'd`).
     Lifetime {
@@ -418,7 +418,7 @@ pub enum GenericParamKind<'hir> {
     },
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct GenericParam<'hir> {
     pub hir_id: HirId,
     pub name: ParamName,
@@ -448,7 +448,7 @@ pub struct GenericParamCount {
 
 /// Represents lifetimes and type parameters attached to a declaration
 /// of a function, enum, trait, etc.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Generics<'hir> {
     pub params: &'hir [GenericParam<'hir>],
     pub where_clause: WhereClause<'hir>,
@@ -501,14 +501,14 @@ impl Generics<'hir> {
 
 /// Synthetic type parameters are converted to another form during lowering; this allows
 /// us to track the original form they had, and is useful for error messages.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum SyntheticTyParamKind {
     ImplTrait,
 }
 
 /// A where-clause in a definition.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct WhereClause<'hir> {
     pub predicates: &'hir [WherePredicate<'hir>],
     // Only valid if predicates aren't empty.
@@ -535,7 +535,7 @@ impl WhereClause<'_> {
 }
 
 /// A single predicate in a where-clause.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum WherePredicate<'hir> {
     /// A type binding (e.g., `for<'c> Foo: Send + Clone + 'c`).
     BoundPredicate(WhereBoundPredicate<'hir>),
@@ -556,7 +556,7 @@ impl WherePredicate<'_> {
 }
 
 /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct WhereBoundPredicate<'hir> {
     pub span: Span,
     /// Any generics from a `for` binding.
@@ -568,7 +568,7 @@ pub struct WhereBoundPredicate<'hir> {
 }
 
 /// A lifetime predicate (e.g., `'a: 'b + 'c`).
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct WhereRegionPredicate<'hir> {
     pub span: Span,
     pub lifetime: Lifetime,
@@ -576,7 +576,7 @@ pub struct WhereRegionPredicate<'hir> {
 }
 
 /// An equality predicate (e.g., `T = int`); currently unsupported.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct WhereEqPredicate<'hir> {
     pub hir_id: HirId,
     pub span: Span,
@@ -584,7 +584,7 @@ pub struct WhereEqPredicate<'hir> {
     pub rhs_ty: &'hir Ty<'hir>,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub struct ModuleItems {
     // Use BTreeSets here so items are in the same order as in the
     // list of all items in Crate
@@ -594,7 +594,7 @@ pub struct ModuleItems {
 }
 
 /// A type representing only the top-level module.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub struct CrateItem<'hir> {
     pub module: Mod<'hir>,
     pub attrs: &'hir [Attribute],
@@ -607,7 +607,7 @@ pub struct CrateItem<'hir> {
 /// For more details, see the [rustc dev guide].
 ///
 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Debug)]
 pub struct Crate<'hir> {
     pub item: CrateItem<'hir>,
     pub exported_macros: &'hir [MacroDef<'hir>],
@@ -715,7 +715,7 @@ impl Crate<'_> {
 /// A macro definition, in this crate or imported from another.
 ///
 /// Not parsed directly, but created on macro import or `macro_rules!` expansion.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct MacroDef<'hir> {
     pub ident: Ident,
     pub vis: Visibility<'hir>,
@@ -728,7 +728,7 @@ pub struct MacroDef<'hir> {
 /// A block of statements `{ .. }`, which may have a label (in this case the
 /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of
 /// the `rules` being anything but `DefaultBlock`.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Block<'hir> {
     /// Statements in a block.
     pub stmts: &'hir [Stmt<'hir>],
@@ -746,7 +746,7 @@ pub struct Block<'hir> {
     pub targeted_by_break: bool,
 }
 
-#[derive(Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Pat<'hir> {
     #[stable_hasher(ignore)]
     pub hir_id: HirId,
@@ -824,7 +824,7 @@ impl Pat<'_> {
 /// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
 /// are treated the same as` x: x, y: ref y, z: ref mut z`,
 /// except `is_shorthand` is true.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct FieldPat<'hir> {
     #[stable_hasher(ignore)]
     pub hir_id: HirId,
@@ -840,7 +840,7 @@ pub struct FieldPat<'hir> {
 /// Explicit binding annotations given in the HIR for a binding. Note
 /// that this is not the final binding *mode* that we infer after type
 /// inference.
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum BindingAnnotation {
     /// No binding annotation given: this means that the final binding mode
     /// will depend on whether we have skipped through a `&` reference
@@ -861,7 +861,7 @@ pub enum BindingAnnotation {
     RefMut,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum RangeEnd {
     Included,
     Excluded,
@@ -876,7 +876,7 @@ impl fmt::Display for RangeEnd {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum PatKind<'hir> {
     /// Represents a wildcard pattern (i.e., `_`).
     Wild,
@@ -932,7 +932,7 @@ pub enum PatKind<'hir> {
     Slice(&'hir [&'hir Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [&'hir Pat<'hir>]),
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum BinOpKind {
     /// The `+` operator (addition).
     Add,
@@ -1066,7 +1066,7 @@ impl Into<ast::BinOpKind> for BinOpKind {
 
 pub type BinOp = Spanned<BinOpKind>;
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum UnOp {
     /// The `*` operator (deferencing).
     UnDeref,
@@ -1095,7 +1095,7 @@ impl UnOp {
 }
 
 /// A statement.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Stmt<'hir> {
     pub hir_id: HirId,
     pub kind: StmtKind<'hir>,
@@ -1103,7 +1103,7 @@ pub struct Stmt<'hir> {
 }
 
 /// The contents of a statement.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum StmtKind<'hir> {
     /// A local (`let`) binding.
     Local(&'hir Local<'hir>),
@@ -1129,7 +1129,7 @@ impl StmtKind<'hir> {
 }
 
 /// Represents a `let` statement (i.e., `let <pat>:<ty> = <expr>;`).
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Local<'hir> {
     pub pat: &'hir Pat<'hir>,
     /// Type annotation, if any (otherwise the type will be inferred).
@@ -1146,7 +1146,7 @@ pub struct Local<'hir> {
 
 /// Represents a single arm of a `match` expression, e.g.
 /// `<pat> (if <guard>) => <body>`.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Arm<'hir> {
     #[stable_hasher(ignore)]
     pub hir_id: HirId,
@@ -1160,12 +1160,12 @@ pub struct Arm<'hir> {
     pub body: &'hir Expr<'hir>,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum Guard<'hir> {
     If(&'hir Expr<'hir>),
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Field<'hir> {
     #[stable_hasher(ignore)]
     pub hir_id: HirId,
@@ -1175,7 +1175,7 @@ pub struct Field<'hir> {
     pub is_shorthand: bool,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum BlockCheckMode {
     DefaultBlock,
     UnsafeBlock(UnsafeSource),
@@ -1183,13 +1183,13 @@ pub enum BlockCheckMode {
     PopUnsafeBlock(UnsafeSource),
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum UnsafeSource {
     CompilerGenerated,
     UserProvided,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Hash, Debug)]
 pub struct BodyId {
     pub hir_id: HirId,
 }
@@ -1215,7 +1215,7 @@ pub struct BodyId {
 ///
 /// All bodies have an **owner**, which can be accessed via the HIR
 /// map using `body_owner_def_id()`.
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Debug)]
 pub struct Body<'hir> {
     pub params: &'hir [Param<'hir>],
     pub value: Expr<'hir>,
@@ -1233,7 +1233,7 @@ impl Body<'hir> {
 }
 
 /// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum GeneratorKind {
     /// An explicit `async` block or the body of an async function.
     Async(AsyncGeneratorKind),
@@ -1256,7 +1256,7 @@ impl fmt::Display for GeneratorKind {
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum AsyncGeneratorKind {
     /// An explicit `async` block written by the user.
     Block,
@@ -1357,14 +1357,14 @@ pub type Lit = Spanned<LitKind>;
 /// These are usually found nested inside types (e.g., array lengths)
 /// or expressions (e.g., repeat counts), and also used to define
 /// explicit discriminant values for enum variants.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
 pub struct AnonConst {
     pub hir_id: HirId,
     pub body: BodyId,
 }
 
 /// An expression.
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug)]
 pub struct Expr<'hir> {
     pub hir_id: HirId,
     pub kind: ExprKind<'hir>,
@@ -1543,7 +1543,7 @@ pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool {
     false
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum ExprKind<'hir> {
     /// A `box x` expression.
     Box(&'hir Expr<'hir>),
@@ -1660,7 +1660,7 @@ pub enum ExprKind<'hir> {
 /// To resolve the path to a `DefId`, call [`qpath_res`].
 ///
 /// [`qpath_res`]: ../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum QPath<'hir> {
     /// Path to a definition, optionally "fully-qualified" with a `Self`
     /// type, if the path points to an associated item in a trait.
@@ -1680,7 +1680,7 @@ pub enum QPath<'hir> {
 }
 
 /// Hints at the original code for a let statement.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
 pub enum LocalSource {
     /// A `match _ { .. }`.
     Normal,
@@ -1702,7 +1702,7 @@ pub enum LocalSource {
 }
 
 /// Hints at the original code for a `match _ { .. }`.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum MatchSource {
     /// A `match _ { .. }`.
@@ -1739,7 +1739,7 @@ impl MatchSource {
 }
 
 /// The loop type that yielded an `ExprKind::Loop`.
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum LoopSource {
     /// A `loop { .. }` loop.
     Loop,
@@ -1761,7 +1761,7 @@ impl LoopSource {
     }
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
 pub enum LoopIdError {
     OutsideLoopScope,
     UnlabeledCfInWhileCondition,
@@ -1780,7 +1780,7 @@ impl fmt::Display for LoopIdError {
     }
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
 pub struct Destination {
     // This is `Some(_)` iff there is an explicit user-specified `label
     pub label: Option<Label>,
@@ -1791,7 +1791,7 @@ pub struct Destination {
 }
 
 /// The yield kind that caused an `ExprKind::Yield`.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)]
 pub enum YieldSource {
     /// An `<expr>.await`.
     Await { expr: Option<HirId> },
@@ -1829,7 +1829,7 @@ impl From<GeneratorKind> for YieldSource {
 
 // N.B., if you change this, you'll probably want to change the corresponding
 // type structure in middle/ty.rs as well.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct MutTy<'hir> {
     pub ty: &'hir Ty<'hir>,
     pub mutbl: Mutability,
@@ -1837,7 +1837,7 @@ pub struct MutTy<'hir> {
 
 /// Represents a function's signature in a trait declaration,
 /// trait implementation, or a free function.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct FnSig<'hir> {
     pub header: FnHeader,
     pub decl: &'hir FnDecl<'hir>,
@@ -1846,7 +1846,7 @@ pub struct FnSig<'hir> {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the node-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
 pub struct TraitItemId {
     pub hir_id: HirId,
 }
@@ -1855,7 +1855,7 @@ pub struct TraitItemId {
 /// possibly including a default implementation. A trait item is
 /// either required (meaning it doesn't have an implementation, just a
 /// signature) or provided (meaning it has a default implementation).
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Debug)]
 pub struct TraitItem<'hir> {
     pub ident: Ident,
     pub hir_id: HirId,
@@ -1866,7 +1866,7 @@ pub struct TraitItem<'hir> {
 }
 
 /// Represents a trait method's body (or just argument names).
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub enum TraitFn<'hir> {
     /// No default body in the trait, just a signature.
     Required(&'hir [Ident]),
@@ -1876,7 +1876,7 @@ pub enum TraitFn<'hir> {
 }
 
 /// Represents a trait method or associated constant or type
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum TraitItemKind<'hir> {
     /// An associated constant with an optional value (otherwise `impl`s must contain a value).
     Const(&'hir Ty<'hir>, Option<BodyId>),
@@ -1890,13 +1890,13 @@ pub enum TraitItemKind<'hir> {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the node-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
 pub struct ImplItemId {
     pub hir_id: HirId,
 }
 
 /// Represents anything within an `impl` block.
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Debug)]
 pub struct ImplItem<'hir> {
     pub ident: Ident,
     pub hir_id: HirId,
@@ -1909,7 +1909,7 @@ pub struct ImplItem<'hir> {
 }
 
 /// Represents various kinds of content within an `impl`.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum ImplItemKind<'hir> {
     /// An associated constant of the given type, set to the constant result
     /// of the expression.
@@ -1947,7 +1947,7 @@ pub const FN_OUTPUT_NAME: Symbol = sym::Output;
 ///    Binding(...),
 /// }
 /// ```
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct TypeBinding<'hir> {
     pub hir_id: HirId,
     #[stable_hasher(project(name))]
@@ -1957,7 +1957,7 @@ pub struct TypeBinding<'hir> {
 }
 
 // Represents the two kinds of type bindings.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum TypeBindingKind<'hir> {
     /// E.g., `Foo<Bar: Send>`.
     Constraint { bounds: &'hir [GenericBound<'hir>] },
@@ -1974,7 +1974,7 @@ impl TypeBinding<'_> {
     }
 }
 
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug)]
 pub struct Ty<'hir> {
     pub hir_id: HirId,
     pub kind: TyKind<'hir>,
@@ -1982,7 +1982,7 @@ pub struct Ty<'hir> {
 }
 
 /// Not represented directly in the AST; referred to by name through a `ty_path`.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum PrimTy {
     Int(IntTy),
@@ -1993,7 +1993,7 @@ pub enum PrimTy {
     Char,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct BareFnTy<'hir> {
     pub unsafety: Unsafety,
     pub abi: Abi,
@@ -2002,7 +2002,7 @@ pub struct BareFnTy<'hir> {
     pub param_names: &'hir [Ident],
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct OpaqueTy<'hir> {
     pub generics: Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
@@ -2011,7 +2011,7 @@ pub struct OpaqueTy<'hir> {
 }
 
 /// From whence the opaque type came.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum OpaqueTyOrigin {
     /// `-> impl Trait`
     FnReturn,
@@ -2024,7 +2024,7 @@ pub enum OpaqueTyOrigin {
 }
 
 /// The various kinds of types recognized by the compiler.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum TyKind<'hir> {
     /// A variable length slice (i.e., `[T]`).
     Slice(&'hir Ty<'hir>),
@@ -2063,7 +2063,7 @@ pub enum TyKind<'hir> {
     Err,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum InlineAsmOperand<'hir> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -2105,7 +2105,7 @@ impl<'hir> InlineAsmOperand<'hir> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct InlineAsm<'hir> {
     pub template: &'hir [InlineAsmTemplatePiece],
     pub operands: &'hir [InlineAsmOperand<'hir>],
@@ -2113,7 +2113,7 @@ pub struct InlineAsm<'hir> {
     pub line_spans: &'hir [Span],
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic, PartialEq)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq)]
 pub struct LlvmInlineAsmOutput {
     pub constraint: Symbol,
     pub is_rw: bool,
@@ -2122,8 +2122,9 @@ pub struct LlvmInlineAsmOutput {
 }
 
 // NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
-// it needs to be `Clone` and use plain `Vec<T>` instead of arena-allocated slice.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic, PartialEq)]
+// it needs to be `Clone` and `Decodable` and use plain `Vec<T>` instead of
+// arena-allocated slice.
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq)]
 pub struct LlvmInlineAsmInner {
     pub asm: Symbol,
     pub asm_str_style: StrStyle,
@@ -2135,7 +2136,7 @@ pub struct LlvmInlineAsmInner {
     pub dialect: LlvmAsmDialect,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct LlvmInlineAsm<'hir> {
     pub inner: LlvmInlineAsmInner,
     pub outputs_exprs: &'hir [Expr<'hir>],
@@ -2143,7 +2144,7 @@ pub struct LlvmInlineAsm<'hir> {
 }
 
 /// Represents a parameter in a function header.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Param<'hir> {
     pub attrs: &'hir [Attribute],
     pub hir_id: HirId,
@@ -2153,7 +2154,7 @@ pub struct Param<'hir> {
 }
 
 /// Represents the header (not the body) of a function declaration.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct FnDecl<'hir> {
     /// The types of the function's parameters.
     ///
@@ -2166,7 +2167,7 @@ pub struct FnDecl<'hir> {
 }
 
 /// Represents what type of implicit self a function has, if any.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum ImplicitSelfKind {
     /// Represents a `fn x(self);`.
     Imm,
@@ -2191,24 +2192,14 @@ impl ImplicitSelfKind {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
 pub enum IsAsync {
     Async,
     NotAsync,
 }
 
-#[derive(
-    Copy,
-    Clone,
-    PartialEq,
-    RustcEncodable,
-    RustcDecodable,
-    Debug,
-    HashStable_Generic,
-    Eq,
-    Hash
-)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
 pub enum Defaultness {
     Default { has_value: bool },
     Final,
@@ -2234,7 +2225,7 @@ impl Defaultness {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum FnRetTy<'hir> {
     /// Return type is not specified.
     ///
@@ -2255,7 +2246,7 @@ impl FnRetTy<'_> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Encodable, Debug)]
 pub struct Mod<'hir> {
     /// A span from the first token past `{` to the last token until `}`.
     /// For `mod foo;`, the inner span ranges from the first token
@@ -2264,23 +2255,23 @@ pub struct Mod<'hir> {
     pub item_ids: &'hir [ItemId],
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct ForeignMod<'hir> {
     pub abi: Abi,
     pub items: &'hir [ForeignItem<'hir>],
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub struct GlobalAsm {
     pub asm: Symbol,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct EnumDef<'hir> {
     pub variants: &'hir [Variant<'hir>],
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Variant<'hir> {
     /// Name of the variant.
     #[stable_hasher(project(name))]
@@ -2297,7 +2288,7 @@ pub struct Variant<'hir> {
     pub span: Span,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum UseKind {
     /// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
     /// Also produced for each element of a list `use`, e.g.
@@ -2319,7 +2310,7 @@ pub enum UseKind {
 /// that the `ref_id` is for. Note that `ref_id`'s value is not the `HirId` of the
 /// trait being referred to but just a unique `HirId` that serves as a key
 /// within the resolution map.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct TraitRef<'hir> {
     pub path: &'hir Path<'hir>,
     // Don't hash the `ref_id`. It is tracked via the thing it is used to access.
@@ -2338,7 +2329,7 @@ impl TraitRef<'_> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct PolyTraitRef<'hir> {
     /// The `'a` in `for<'a> Foo<&'a T>`.
     pub bound_generic_params: &'hir [GenericParam<'hir>],
@@ -2351,7 +2342,7 @@ pub struct PolyTraitRef<'hir> {
 
 pub type Visibility<'hir> = Spanned<VisibilityKind<'hir>>;
 
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Debug)]
 pub enum VisibilityKind<'hir> {
     Public,
     Crate(CrateSugar),
@@ -2384,7 +2375,7 @@ impl VisibilityKind<'_> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct StructField<'hir> {
     pub span: Span,
     #[stable_hasher(project(name))]
@@ -2404,7 +2395,7 @@ impl StructField<'_> {
 }
 
 /// Fields and constructor IDs of enum variants and structs.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum VariantData<'hir> {
     /// A struct variant.
     ///
@@ -2441,7 +2432,7 @@ impl VariantData<'hir> {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the node-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, Encodable, Debug)]
 pub struct ItemId {
     pub id: HirId,
 }
@@ -2449,7 +2440,7 @@ pub struct ItemId {
 /// An item
 ///
 /// The name might be a dummy name in case of anonymous items
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Debug)]
 pub struct Item<'hir> {
     pub ident: Ident,
     pub hir_id: HirId,
@@ -2460,7 +2451,7 @@ pub struct Item<'hir> {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum Unsafety {
     Unsafe,
     Normal,
@@ -2485,13 +2476,13 @@ impl fmt::Display for Unsafety {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum Constness {
     Const,
     NotConst,
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
 pub struct FnHeader {
     pub unsafety: Unsafety,
     pub constness: Constness,
@@ -2508,7 +2499,7 @@ impl FnHeader {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum ItemKind<'hir> {
     /// An `extern crate` item, with optional *original* crate name if the crate was renamed.
     ///
@@ -2590,7 +2581,7 @@ impl ItemKind<'_> {
 /// type or method, and whether it is public). This allows other
 /// passes to find the impl they want without loading the ID (which
 /// means fewer edges in the incremental compilation graph).
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub struct TraitItemRef {
     pub id: TraitItemId,
     #[stable_hasher(project(name))]
@@ -2606,7 +2597,7 @@ pub struct TraitItemRef {
 /// type or method, and whether it is public). This allows other
 /// passes to find the impl they want without loading the ID (which
 /// means fewer edges in the incremental compilation graph).
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct ImplItemRef<'hir> {
     pub id: ImplItemId,
     #[stable_hasher(project(name))]
@@ -2617,14 +2608,14 @@ pub struct ImplItemRef<'hir> {
     pub defaultness: Defaultness,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum AssocItemKind {
     Const,
     Fn { has_self: bool },
     Type,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub struct ForeignItem<'hir> {
     #[stable_hasher(project(name))]
     pub ident: Ident,
@@ -2636,7 +2627,7 @@ pub struct ForeignItem<'hir> {
 }
 
 /// An item within an `extern` block.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Debug, HashStable_Generic)]
 pub enum ForeignItemKind<'hir> {
     /// A foreign function.
     Fn(&'hir FnDecl<'hir>, &'hir [Ident], Generics<'hir>),
@@ -2647,7 +2638,7 @@ pub enum ForeignItemKind<'hir> {
 }
 
 /// A variable captured by a closure.
-#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
 pub struct Upvar {
     // First span where it is accessed (there can be multiple).
     pub span: Span,
@@ -2658,7 +2649,7 @@ pub type CaptureModeMap = NodeMap<CaptureBy>;
 // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
 // has length > 0 if the trait is found through an chain of imports, starting with the
 // import/use statement in the scope where the trait is used.
-#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
+#[derive(Encodable, Decodable, Clone, Debug)]
 pub struct TraitCandidate {
     pub def_id: DefId,
     pub import_ids: SmallVec<[LocalDefId; 1]>,
diff --git a/src/librustc_hir/hir_id.rs b/src/librustc_hir/hir_id.rs
index d782c3dd70a..fea850c12d9 100644
--- a/src/librustc_hir/hir_id.rs
+++ b/src/librustc_hir/hir_id.rs
@@ -11,7 +11,8 @@ use std::fmt;
 /// the `local_id` part of the `HirId` changing, which is a very useful property in
 /// incremental compilation where we have to persist things through changes to
 /// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Encodable, Decodable)]
 pub struct HirId {
     pub owner: LocalDefId,
     pub local_id: ItemLocalId,
diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs
index 7f473a45848..b09657bd9b4 100644
--- a/src/librustc_hir/lang_items.rs
+++ b/src/librustc_hir/lang_items.rs
@@ -45,7 +45,7 @@ macro_rules! language_item_table {
 
         enum_from_u32! {
             /// A representation of all the valid language items in Rust.
-            #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+            #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
             pub enum LangItem {
                 $($variant,)*
             }
@@ -165,6 +165,7 @@ language_item_table! {
     BoolImplItem,                  sym::bool,               bool_impl,               Target::Impl;
     CharImplItem,                  sym::char,               char_impl,               Target::Impl;
     StrImplItem,                   sym::str,                str_impl,                Target::Impl;
+    ArrayImplItem,                 sym::array,              array_impl,              Target::Impl;
     SliceImplItem,                 sym::slice,              slice_impl,              Target::Impl;
     SliceU8ImplItem,               sym::slice_u8,           slice_u8_impl,           Target::Impl;
     StrAllocImplItem,              sym::str_alloc,          str_alloc_impl,          Target::Impl;
diff --git a/src/librustc_hir/lib.rs b/src/librustc_hir/lib.rs
index 52131cb3d3d..a64565b20e7 100644
--- a/src/librustc_hir/lib.rs
+++ b/src/librustc_hir/lib.rs
@@ -7,10 +7,12 @@
 #![feature(const_panic)]
 #![feature(in_band_lifetimes)]
 #![feature(or_patterns)]
-#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
+extern crate rustc_macros;
+
+#[macro_use]
 extern crate rustc_data_structures;
 
 mod arena;
diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml
index 60a87078d63..2b597c7da80 100644
--- a/src/librustc_incremental/Cargo.toml
+++ b/src/librustc_incremental/Cargo.toml
@@ -18,6 +18,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_serialize = { path = "../librustc_serialize" }
 rustc_ast = { path = "../librustc_ast" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_span = { path = "../librustc_span" }
 rustc_fs_util = { path = "../librustc_fs_util" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs
index ea0fd4eb7ee..81e5410978d 100644
--- a/src/librustc_incremental/persist/data.rs
+++ b/src/librustc_incremental/persist/data.rs
@@ -1,8 +1,9 @@
 //! The data that we will serialize and deserialize.
 
+use rustc_macros::{Decodable, Encodable};
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Encodable, Decodable)]
 pub struct SerializedWorkProduct {
     /// node that produced the work-product
     pub id: WorkProductId,
diff --git a/src/librustc_index/Cargo.toml b/src/librustc_index/Cargo.toml
index 00b23760182..8aaf1cb9cbc 100644
--- a/src/librustc_index/Cargo.toml
+++ b/src/librustc_index/Cargo.toml
@@ -10,5 +10,6 @@ path = "lib.rs"
 doctest = false
 
 [dependencies]
-rustc_serialize = { path = "../librustc_serialize" }
 arrayvec = "0.5.1"
+rustc_serialize = { path = "../librustc_serialize" }
+rustc_macros = { path = "../librustc_macros" }
diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs
index e4b7c24a249..c43d1a6830d 100644
--- a/src/librustc_index/bit_set.rs
+++ b/src/librustc_index/bit_set.rs
@@ -7,6 +7,8 @@ use std::mem;
 use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
 use std::slice;
 
+use rustc_macros::{Decodable, Encodable};
+
 #[cfg(test)]
 mod tests;
 
@@ -26,7 +28,7 @@ pub const WORD_BITS: usize = WORD_BYTES * 8;
 /// will panic if the bitsets have differing domain sizes.
 ///
 /// [`GrowableBitSet`]: struct.GrowableBitSet.html
-#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Eq, PartialEq, Decodable, Encodable)]
 pub struct BitSet<T: Idx> {
     domain_size: usize,
     words: Vec<Word>,
@@ -700,7 +702,7 @@ impl<T: Idx> GrowableBitSet<T> {
 ///
 /// All operations that involve a row and/or column index will panic if the
 /// index exceeds the relevant bound.
-#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Eq, PartialEq, Decodable, Encodable)]
 pub struct BitMatrix<R: Idx, C: Idx> {
     num_rows: usize,
     num_columns: usize,
@@ -1108,7 +1110,7 @@ impl std::fmt::Debug for FiniteBitSet<u128> {
 
 /// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
 /// representable by `T` are considered set.
-#[derive(Copy, Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+#[derive(Copy, Clone, Eq, PartialEq, Decodable, Encodable)]
 pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);
 
 impl<T: FiniteBitSetTy> FiniteBitSet<T> {
diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs
index c5dedab9793..63f63133a2c 100644
--- a/src/librustc_index/vec.rs
+++ b/src/librustc_index/vec.rs
@@ -320,14 +320,14 @@ macro_rules! newtype_index {
                    derive [$($derives:ident,)+]
                    $($tokens:tt)*) => (
         $crate::newtype_index!(
-            @derives      [$($derives,)+ RustcEncodable,]
+            @derives      [$($derives,)+]
             @attrs        [$(#[$attrs])*]
             @type         [$type]
             @max          [$max]
             @vis          [$v]
             @debug_format [$debug_format]
                           $($tokens)*);
-        $crate::newtype_index!(@decodable $type);
+        $crate::newtype_index!(@serializable $type);
     );
 
     // The case where no derives are added, but encodable is overridden. Don't
@@ -357,22 +357,27 @@ macro_rules! newtype_index {
      @debug_format [$debug_format:tt]
                    $($tokens:tt)*) => (
         $crate::newtype_index!(
-            @derives      [RustcEncodable,]
+            @derives      []
             @attrs        [$(#[$attrs])*]
             @type         [$type]
             @max          [$max]
             @vis          [$v]
             @debug_format [$debug_format]
                           $($tokens)*);
-        $crate::newtype_index!(@decodable $type);
+        $crate::newtype_index!(@serializable $type);
     );
 
-    (@decodable $type:ident) => (
-        impl ::rustc_serialize::Decodable for $type {
-            fn decode<D: ::rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+    (@serializable $type:ident) => (
+        impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for $type {
+            fn decode(d: &mut D) -> Result<Self, D::Error> {
                 d.read_u32().map(Self::from_u32)
             }
         }
+        impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for $type {
+            fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+                e.emit_u32(self.private)
+            }
+        }
     );
 
     // Rewrite final without comma to one that includes comma
@@ -483,14 +488,20 @@ pub struct IndexVec<I: Idx, T> {
 // not the phantom data.
 unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {}
 
-impl<I: Idx, T: Encodable> Encodable for IndexVec<I, T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for IndexVec<I, T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        Encodable::encode(&self.raw, s)
+    }
+}
+
+impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for &IndexVec<I, T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         Encodable::encode(&self.raw, s)
     }
 }
 
-impl<I: Idx, T: Decodable> Decodable for IndexVec<I, T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
+impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> {
+    fn decode(d: &mut D) -> Result<Self, D::Error> {
         Decodable::decode(d).map(|v| IndexVec { raw: v, _marker: PhantomData })
     }
 }
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_infer/infer/free_regions.rs b/src/librustc_infer/infer/free_regions.rs
index d975038b010..ffe5fb172be 100644
--- a/src/librustc_infer/infer/free_regions.rs
+++ b/src/librustc_infer/infer/free_regions.rs
@@ -7,17 +7,14 @@ use rustc_data_structures::transitive_relation::TransitiveRelation;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Lift, Region, TyCtxt};
 
-/// Combines a `region::ScopeTree` (which governs relationships between
-/// scopes) and a `FreeRegionMap` (which governs relationships between
-/// free regions) to yield a complete relation between concrete
-/// regions.
+/// Combines a `FreeRegionMap` and a `TyCtxt`.
 ///
 /// This stuff is a bit convoluted and should be refactored, but as we
 /// transition to NLL, it'll all go away anyhow.
 pub struct RegionRelations<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
-    /// The context used to fetch the region maps.
+    /// The context used for debug messages
     pub context: DefId,
 
     /// Free-region relationships.
@@ -34,7 +31,7 @@ impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)]
+#[derive(Clone, Debug, Default)]
 pub struct FreeRegionMap<'tcx> {
     // Stores the relation `a < b`, where `a` and `b` are regions.
     //
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_macros/src/lib.rs b/src/librustc_macros/src/lib.rs
index 6b30ae42a19..7fb3b0e7ea6 100644
--- a/src/librustc_macros/src/lib.rs
+++ b/src/librustc_macros/src/lib.rs
@@ -8,6 +8,7 @@ use proc_macro::TokenStream;
 mod hash_stable;
 mod lift;
 mod query;
+mod serialize;
 mod symbols;
 mod type_foldable;
 
@@ -27,5 +28,11 @@ decl_derive!(
     hash_stable::hash_stable_generic_derive
 );
 
+decl_derive!([Decodable] => serialize::decodable_derive);
+decl_derive!([Encodable] => serialize::encodable_derive);
+decl_derive!([TyDecodable] => serialize::type_decodable_derive);
+decl_derive!([TyEncodable] => serialize::type_encodable_derive);
+decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive);
+decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive);
 decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive);
 decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
diff --git a/src/librustc_macros/src/serialize.rs b/src/librustc_macros/src/serialize.rs
new file mode 100644
index 00000000000..dbeb3c75504
--- /dev/null
+++ b/src/librustc_macros/src/serialize.rs
@@ -0,0 +1,290 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::parse_quote;
+
+pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    let decoder_ty = quote! { __D };
+    if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
+        s.add_impl_generic(parse_quote! { 'tcx });
+    }
+    s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx>});
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    decodable_body(s, decoder_ty)
+}
+
+pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
+        s.add_impl_generic(parse_quote! { 'tcx });
+    }
+    s.add_impl_generic(parse_quote! { '__a });
+    let decoder_ty = quote! { DecodeContext<'__a, 'tcx> };
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    decodable_body(s, decoder_ty)
+}
+
+pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    let decoder_ty = quote! { __D };
+    s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder});
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    decodable_body(s, decoder_ty)
+}
+
+fn decodable_body(
+    s: synstructure::Structure<'_>,
+    decoder_ty: TokenStream,
+) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+    let ty_name = s.ast().ident.to_string();
+    let decode_body = match s.variants() {
+        [vi] => {
+            let construct = vi.construct(|field, index| decode_field(field, index, true));
+            let n_fields = vi.ast().fields.len();
+            quote! {
+                ::rustc_serialize::Decoder::read_struct(
+                    __decoder,
+                    #ty_name,
+                    #n_fields,
+                    |__decoder| { ::std::result::Result::Ok(#construct) },
+                )
+            }
+        }
+        variants => {
+            let match_inner: TokenStream = variants
+                .iter()
+                .enumerate()
+                .map(|(idx, vi)| {
+                    let construct = vi.construct(|field, index| decode_field(field, index, false));
+                    quote! { #idx => { ::std::result::Result::Ok(#construct) } }
+                })
+                .collect();
+            let names: TokenStream = variants
+                .iter()
+                .map(|vi| {
+                    let variant_name = vi.ast().ident.to_string();
+                    quote!(#variant_name,)
+                })
+                .collect();
+            let message = format!(
+                "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                ty_name,
+                variants.len()
+            );
+            quote! {
+                ::rustc_serialize::Decoder::read_enum(
+                    __decoder,
+                    #ty_name,
+                    |__decoder| {
+                        ::rustc_serialize::Decoder::read_enum_variant(
+                            __decoder,
+                            &[#names],
+                            |__decoder, __variant_idx| {
+                                match __variant_idx {
+                                    #match_inner
+                                    _ => return ::std::result::Result::Err(
+                                        ::rustc_serialize::Decoder::error(__decoder, #message)),
+                                }
+                            })
+                    }
+                )
+            }
+        }
+    };
+
+    s.bound_impl(
+        quote!(::rustc_serialize::Decodable<#decoder_ty>),
+        quote! {
+            fn decode(
+                __decoder: &mut #decoder_ty,
+            ) -> ::std::result::Result<Self, <#decoder_ty as ::rustc_serialize::Decoder>::Error> {
+                #decode_body
+            }
+        },
+    )
+}
+
+fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream {
+    let decode_inner_method = if let syn::Type::Reference(_) = field.ty {
+        quote! { ::rustc_middle::ty::codec::RefDecodable::decode }
+    } else {
+        quote! { ::rustc_serialize::Decodable::decode }
+    };
+    let (decode_method, opt_field_name) = if is_struct {
+        let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string());
+        (
+            proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()),
+            quote! { #field_name, },
+        )
+    } else {
+        (
+            proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()),
+            quote! {},
+        )
+    };
+
+    quote! {
+        match ::rustc_serialize::Decoder::#decode_method(
+            __decoder, #opt_field_name #index, #decode_inner_method) {
+            ::std::result::Result::Ok(__res) => __res,
+            ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
+        }
+    }
+}
+
+pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
+        s.add_impl_generic(parse_quote! {'tcx});
+    }
+    let encoder_ty = quote! { __E };
+    s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx>});
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    encodable_body(s, encoder_ty, false)
+}
+
+pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
+        s.add_impl_generic(parse_quote! {'tcx});
+    }
+    s.add_impl_generic(parse_quote! { '__a });
+    let encoder_ty = quote! { EncodeContext<'__a, 'tcx> };
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    encodable_body(s, encoder_ty, true)
+}
+
+pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    let encoder_ty = quote! { __E };
+    s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder});
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    encodable_body(s, encoder_ty, false)
+}
+
+fn encodable_body(
+    mut s: synstructure::Structure<'_>,
+    encoder_ty: TokenStream,
+    allow_unreachable_code: bool,
+) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    s.bind_with(|binding| {
+        // Handle the lack of a blanket reference impl.
+        if let syn::Type::Reference(_) = binding.ast().ty {
+            synstructure::BindStyle::Move
+        } else {
+            synstructure::BindStyle::Ref
+        }
+    });
+
+    let ty_name = s.ast().ident.to_string();
+    let encode_body = match s.variants() {
+        [_] => {
+            let mut field_idx = 0usize;
+            let encode_inner = s.each_variant(|vi| {
+                vi.bindings()
+                    .iter()
+                    .map(|binding| {
+                        let bind_ident = &binding.binding;
+                        let field_name = binding
+                            .ast()
+                            .ident
+                            .as_ref()
+                            .map_or_else(|| field_idx.to_string(), |i| i.to_string());
+                        let result = quote! {
+                            match ::rustc_serialize::Encoder::emit_struct_field(
+                                __encoder,
+                                #field_name,
+                                #field_idx,
+                                |__encoder|
+                                ::rustc_serialize::Encodable::encode(#bind_ident, __encoder),
+                            ) {
+                                ::std::result::Result::Ok(()) => (),
+                                ::std::result::Result::Err(__err)
+                                    => return ::std::result::Result::Err(__err),
+                            }
+                        };
+                        field_idx += 1;
+                        result
+                    })
+                    .collect::<TokenStream>()
+            });
+            quote! {
+                ::rustc_serialize::Encoder::emit_struct(__encoder, #ty_name, #field_idx, |__encoder| {
+                    ::std::result::Result::Ok(match *self { #encode_inner })
+                })
+            }
+        }
+        _ => {
+            let mut variant_idx = 0usize;
+            let encode_inner = s.each_variant(|vi| {
+                let variant_name = vi.ast().ident.to_string();
+                let mut field_idx = 0usize;
+
+                let encode_fields: TokenStream = vi
+                    .bindings()
+                    .iter()
+                    .map(|binding| {
+                        let bind_ident = &binding.binding;
+                        let result = quote! {
+                            match ::rustc_serialize::Encoder::emit_enum_variant_arg(
+                                __encoder,
+                                #field_idx,
+                                |__encoder|
+                                ::rustc_serialize::Encodable::encode(#bind_ident, __encoder),
+                            ) {
+                                ::std::result::Result::Ok(()) => (),
+                                ::std::result::Result::Err(__err)
+                                    => return ::std::result::Result::Err(__err),
+                            }
+                        };
+                        field_idx += 1;
+                        result
+                    })
+                    .collect();
+
+                let result = quote! { ::rustc_serialize::Encoder::emit_enum_variant(
+                    __encoder,
+                   #variant_name,
+                   #variant_idx,
+                   #field_idx,
+                   |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
+                ) };
+                variant_idx += 1;
+                result
+            });
+            quote! {
+                ::rustc_serialize::Encoder::emit_enum(__encoder, #ty_name, |__encoder| {
+                    match *self {
+                        #encode_inner
+                    }
+                })
+            }
+        }
+    };
+
+    let lints = if allow_unreachable_code {
+        quote! { #![allow(unreachable_code)] }
+    } else {
+        quote! {}
+    };
+
+    s.bound_impl(
+        quote!(::rustc_serialize::Encodable<#encoder_ty>),
+        quote! {
+            fn encode(
+                &self,
+                __encoder: &mut #encoder_ty,
+            ) -> ::std::result::Result<(), <#encoder_ty as ::rustc_serialize::Encoder>::Error> {
+                #lints
+                #encode_body
+            }
+        },
+    )
+}
diff --git a/src/librustc_macros/src/symbols.rs b/src/librustc_macros/src/symbols.rs
index 2e9b3a2a256..352665f0ab1 100644
--- a/src/librustc_macros/src/symbols.rs
+++ b/src/librustc_macros/src/symbols.rs
@@ -167,7 +167,7 @@ pub fn symbols(input: TokenStream) -> TokenStream {
             }
         }
 
-        macro_rules! symbols {
+        macro_rules! define_symbols {
             () => {
                 #symbols_stream
 
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index 2c0e2aa39fd..6e3e4e55e42 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -23,6 +23,7 @@ rustc_hir = { path = "../librustc_hir" }
 rustc_hir_pretty = { path = "../librustc_hir_pretty" }
 rustc_target = { path = "../librustc_target" }
 rustc_index = { path = "../librustc_index" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_serialize = { path = "../librustc_serialize" }
 stable_deref_trait = "1.0.0"
 rustc_ast = { path = "../librustc_ast" }
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 059ae340bcf..e50fa34554d 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -16,6 +16,8 @@
 extern crate proc_macro;
 
 #[macro_use]
+extern crate rustc_macros;
+#[macro_use]
 extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_data_structures;
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 8aea9a9f588..27f59ec2638 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -7,7 +7,7 @@ use crate::rmeta::*;
 use rustc_ast::ast;
 use rustc_attr as attr;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, OnceCell};
@@ -15,7 +15,7 @@ use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathTable;
 use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc_hir::lang_items;
@@ -26,11 +26,11 @@ use rustc_middle::middle::cstore::{CrateSource, ExternCrate};
 use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
-use rustc_middle::mir::{self, interpret, Body, Promoted};
+use rustc_middle::mir::{self, Body, Promoted};
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::util::common::record_time;
-use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder, UseSpecializedDecodable};
+use rustc_serialize::{opaque, Decodable, Decoder};
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnDataDecodeMode;
 use rustc_span::source_map::{respan, Spanned};
@@ -229,7 +229,7 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) {
     }
 }
 
-impl<'a, 'tcx, T: Decodable> Lazy<T, ()> {
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<T> {
     fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
         let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
@@ -237,7 +237,7 @@ impl<'a, 'tcx, T: Decodable> Lazy<T, ()> {
     }
 }
 
-impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T], usize> {
+impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<[T]> {
     fn decode<M: Metadata<'a, 'tcx>>(
         self,
         metadata: M,
@@ -278,6 +278,8 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
+    const CLEAR_CROSS_CRATE: bool = true;
+
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx.expect("missing TyCtxt in DecodeContext")
@@ -351,68 +353,92 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
     fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
         if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
     }
-}
 
-impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T, ()>> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<Lazy<T>, Self::Error> {
-        self.read_lazy_with_meta(())
+    fn decode_alloc_id(&mut self) -> Result<rustc_middle::mir::interpret::AllocId, Self::Error> {
+        if let Some(alloc_decoding_session) = self.alloc_decoding_session {
+            alloc_decoding_session.decode_alloc_id(self)
+        } else {
+            bug!("Attempting to decode interpret::AllocId without CrateMetadata")
+        }
     }
 }
 
-impl<'a, 'tcx, T> SpecializedDecoder<Lazy<[T], usize>> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<Lazy<[T]>, Self::Error> {
-        let len = self.read_usize()?;
-        if len == 0 { Ok(Lazy::empty()) } else { self.read_lazy_with_meta(len) }
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for CrateNum {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<CrateNum, String> {
+        let cnum = CrateNum::from_u32(d.read_u32()?);
+        Ok(d.map_encoded_cnum_to_current(cnum))
     }
 }
 
-impl<'a, 'tcx, I: Idx, T> SpecializedDecoder<Lazy<Table<I, T>, usize>> for DecodeContext<'a, 'tcx>
-where
-    Option<T>: FixedSizeEncoding,
-{
-    fn specialized_decode(&mut self) -> Result<Lazy<Table<I, T>>, Self::Error> {
-        let len = self.read_usize()?;
-        self.read_lazy_with_meta(len)
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefIndex {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefIndex, String> {
+        Ok(DefIndex::from_u32(d.read_u32()?))
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<DefId> for DecodeContext<'a, 'tcx> {
-    #[inline]
-    fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
-        let krate = CrateNum::decode(self)?;
-        let index = DefIndex::decode(self)?;
-
-        Ok(DefId { krate, index })
+impl<'a, 'tcx> FingerprintDecoder for DecodeContext<'a, 'tcx> {
+    fn decode_fingerprint(&mut self) -> Result<Fingerprint, String> {
+        Fingerprint::decode_opaque(&mut self.opaque)
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
-    #[inline]
-    fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
-        Ok(DefIndex::from_u32(self.read_u32()?))
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<SyntaxContext, String> {
+        let cdata = decoder.cdata();
+        let sess = decoder.sess.unwrap();
+        let cname = cdata.root.name;
+        rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| {
+            debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
+            Ok(cdata
+                .root
+                .syntax_contexts
+                .get(&cdata, id)
+                .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
+                .decode((&cdata, sess)))
+        })
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<LocalDefId> for DecodeContext<'a, 'tcx> {
-    #[inline]
-    fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
-        Ok(DefId::decode(self)?.expect_local())
-    }
-}
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnId, String> {
+        let local_cdata = decoder.cdata();
+        let sess = decoder.sess.unwrap();
+        let expn_cnum = Cell::new(None);
+        let get_ctxt = |cnum| {
+            expn_cnum.set(Some(cnum));
+            if cnum == LOCAL_CRATE {
+                &local_cdata.hygiene_context
+            } else {
+                &local_cdata.cstore.get_crate_data(cnum).cdata.hygiene_context
+            }
+        };
 
-impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
-        if let Some(alloc_decoding_session) = self.alloc_decoding_session {
-            alloc_decoding_session.decode_alloc_id(self)
-        } else {
-            bug!("Attempting to decode interpret::AllocId without CrateMetadata")
-        }
+        rustc_span::hygiene::decode_expn_id(
+            decoder,
+            ExpnDataDecodeMode::Metadata(get_ctxt),
+            |_this, index| {
+                let cnum = expn_cnum.get().unwrap();
+                // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s
+                // are stored in the owning crate, to avoid duplication.
+                let crate_data = if cnum == LOCAL_CRATE {
+                    local_cdata
+                } else {
+                    local_cdata.cstore.get_crate_data(cnum)
+                };
+                Ok(crate_data
+                    .root
+                    .expn_data
+                    .get(&crate_data, index)
+                    .unwrap()
+                    .decode((&crate_data, sess)))
+            },
+        )
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
-        let tag = u8::decode(self)?;
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Span, String> {
+        let tag = u8::decode(decoder)?;
 
         if tag == TAG_INVALID_SPAN {
             return Ok(DUMMY_SP);
@@ -420,12 +446,12 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
 
         debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN);
 
-        let lo = BytePos::decode(self)?;
-        let len = BytePos::decode(self)?;
-        let ctxt = SyntaxContext::decode(self)?;
+        let lo = BytePos::decode(decoder)?;
+        let len = BytePos::decode(decoder)?;
+        let ctxt = SyntaxContext::decode(decoder)?;
         let hi = lo + len;
 
-        let sess = if let Some(sess) = self.sess {
+        let sess = if let Some(sess) = decoder.sess {
             sess
         } else {
             bug!("Cannot decode Span without Session.")
@@ -460,22 +486,22 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
         // we can call `imported_source_files` for the proper crate, and binary search
         // through the returned slice using our span.
         let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL {
-            self.cdata().imported_source_files(sess)
+            decoder.cdata().imported_source_files(sess)
         } else {
             // When we encode a proc-macro crate, all `Span`s should be encoded
             // with `TAG_VALID_SPAN_LOCAL`
-            if self.cdata().root.is_proc_macro_crate() {
+            if decoder.cdata().root.is_proc_macro_crate() {
                 // Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE
                 // since we don't have `cnum_map` populated.
-                let cnum = u32::decode(self)?;
+                let cnum = u32::decode(decoder)?;
                 panic!(
                     "Decoding of crate {:?} tried to access proc-macro dep {:?}",
-                    self.cdata().root.name,
+                    decoder.cdata().root.name,
                     cnum
                 );
             }
             // tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above
-            let cnum = CrateNum::decode(self)?;
+            let cnum = CrateNum::decode(decoder)?;
             debug!(
                 "SpecializedDecoder<Span>::specialized_decode: loading source files from cnum {:?}",
                 cnum
@@ -485,16 +511,16 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
             // not worth it to maintain a per-CrateNum cache for `last_source_file_index`.
             // We just set it to 0, to ensure that we don't try to access something out
             // of bounds for our initial 'guess'
-            self.last_source_file_index = 0;
+            decoder.last_source_file_index = 0;
 
-            let foreign_data = self.cdata().cstore.get_crate_data(cnum);
+            let foreign_data = decoder.cdata().cstore.get_crate_data(cnum);
             foreign_data.imported_source_files(sess)
         };
 
         let source_file = {
             // Optimize for the case that most spans within a translated item
             // originate from the same source_file.
-            let last_source_file = &imported_source_files[self.last_source_file_index];
+            let last_source_file = &imported_source_files[decoder.last_source_file_index];
 
             if lo >= last_source_file.original_start_pos && lo <= last_source_file.original_end_pos
             {
@@ -507,7 +533,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
                 // Don't try to cache the index for foreign spans,
                 // as this would require a map from CrateNums to indices
                 if tag == TAG_VALID_SPAN_LOCAL {
-                    self.last_source_file_index = index;
+                    decoder.last_source_file_index = index;
                 }
                 &imported_source_files[index]
             }
@@ -540,19 +566,37 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<Fingerprint> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<Fingerprint, Self::Error> {
-        Fingerprint::decode_opaque(&mut self.opaque)
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+        ty::codec::RefDecodable::decode(d)
+    }
+}
+
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
+    for Lazy<T>
+{
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+        decoder.read_lazy_with_meta(())
     }
 }
 
-impl<'a, 'tcx, T> SpecializedDecoder<mir::ClearCrossCrate<T>> for DecodeContext<'a, 'tcx>
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
+    for Lazy<[T]>
+{
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+        let len = decoder.read_usize()?;
+        if len == 0 { Ok(Lazy::empty()) } else { decoder.read_lazy_with_meta(len) }
+    }
+}
+
+impl<'a, 'tcx, I: Idx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
+    for Lazy<Table<I, T>>
 where
-    mir::ClearCrossCrate<T>: UseSpecializedDecodable,
+    Option<T>: FixedSizeEncoding,
 {
-    #[inline]
-    fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, Self::Error> {
-        Ok(mir::ClearCrossCrate::Clear)
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+        let len = decoder.read_usize()?;
+        decoder.read_lazy_with_meta(len)
     }
 }
 
@@ -1840,57 +1884,3 @@ fn macro_kind(raw: &ProcMacro) -> MacroKind {
         ProcMacro::Bang { .. } => MacroKind::Bang,
     }
 }
-
-impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<SyntaxContext, Self::Error> {
-        let cdata = self.cdata();
-        let sess = self.sess.unwrap();
-        let cname = cdata.root.name;
-        rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| {
-            debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
-            Ok(cdata
-                .root
-                .syntax_contexts
-                .get(&cdata, id)
-                .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
-                .decode((&cdata, sess)))
-        })
-    }
-}
-
-impl<'a, 'tcx> SpecializedDecoder<ExpnId> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<ExpnId, Self::Error> {
-        let local_cdata = self.cdata();
-        let sess = self.sess.unwrap();
-        let expn_cnum = Cell::new(None);
-        let get_ctxt = |cnum| {
-            expn_cnum.set(Some(cnum));
-            if cnum == LOCAL_CRATE {
-                &local_cdata.hygiene_context
-            } else {
-                &local_cdata.cstore.get_crate_data(cnum).cdata.hygiene_context
-            }
-        };
-
-        rustc_span::hygiene::decode_expn_id(
-            self,
-            ExpnDataDecodeMode::Metadata(get_ctxt),
-            |_this, index| {
-                let cnum = expn_cnum.get().unwrap();
-                // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s
-                // are stored in the owning crate, to avoid duplication.
-                let crate_data = if cnum == LOCAL_CRATE {
-                    local_cdata
-                } else {
-                    local_cdata.cstore.get_crate_data(cnum)
-                };
-                Ok(crate_data
-                    .root
-                    .expn_data
-                    .get(&crate_data, index)
-                    .unwrap()
-                    .decode((&crate_data, sess)))
-            },
-        )
-    }
-}
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index 6723e236a1f..e97e598765e 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -3,7 +3,7 @@ use crate::rmeta::*;
 
 use log::{debug, trace};
 use rustc_ast::ast;
-use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fingerprint::{Fingerprint, FingerprintEncoder};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{join, Lrc};
@@ -23,11 +23,11 @@ use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
 };
-use rustc_middle::mir::{self, interpret};
+use rustc_middle::mir::interpret;
 use rustc_middle::traits::specialization_graph;
-use rustc_middle::ty::codec::{self as ty_codec, TyEncoder};
+use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
-use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder, UseSpecializedEncodable};
+use rustc_serialize::{opaque, Encodable, Encoder};
 use rustc_session::config::CrateType;
 use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext};
 use rustc_span::source_map::Spanned;
@@ -38,7 +38,7 @@ use std::hash::Hash;
 use std::num::NonZeroUsize;
 use std::path::Path;
 
-struct EncodeContext<'a, 'tcx> {
+pub(super) struct EncodeContext<'a, 'tcx> {
     opaque: opaque::Encoder,
     tcx: TyCtxt<'tcx>,
 
@@ -107,100 +107,87 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, T> SpecializedEncoder<Lazy<T, ()>> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> {
-        self.emit_lazy_distance(*lazy)
+impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
+    for Lazy<T>
+{
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        e.emit_lazy_distance(*self)
     }
 }
 
-impl<'a, 'tcx, T> SpecializedEncoder<Lazy<[T], usize>> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, lazy: &Lazy<[T]>) -> Result<(), Self::Error> {
-        self.emit_usize(lazy.meta)?;
-        if lazy.meta == 0 {
+impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
+    for Lazy<[T]>
+{
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        e.emit_usize(self.meta)?;
+        if self.meta == 0 {
             return Ok(());
         }
-        self.emit_lazy_distance(*lazy)
+        e.emit_lazy_distance(*self)
     }
 }
 
-impl<'a, 'tcx, I: Idx, T> SpecializedEncoder<Lazy<Table<I, T>, usize>> for EncodeContext<'a, 'tcx>
+impl<'a, 'tcx, I: Idx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
+    for Lazy<Table<I, T>>
 where
     Option<T>: FixedSizeEncoding,
 {
-    fn specialized_encode(&mut self, lazy: &Lazy<Table<I, T>>) -> Result<(), Self::Error> {
-        self.emit_usize(lazy.meta)?;
-        self.emit_lazy_distance(*lazy)
-    }
-}
-
-impl<'a, 'tcx> SpecializedEncoder<CrateNum> for EncodeContext<'a, 'tcx> {
-    #[inline]
-    fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> {
-        self.emit_u32(cnum.as_u32())
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        e.emit_usize(self.meta)?;
+        e.emit_lazy_distance(*self)
     }
 }
 
-impl<'a, 'tcx> SpecializedEncoder<DefId> for EncodeContext<'a, 'tcx> {
-    #[inline]
-    fn specialized_encode(&mut self, def_id: &DefId) -> Result<(), Self::Error> {
-        let DefId { krate, index } = *def_id;
-
-        krate.encode(self)?;
-        index.encode(self)
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefIndex {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        s.emit_u32(self.as_u32())
     }
 }
 
-impl<'a, 'tcx> SpecializedEncoder<SyntaxContext> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, ctxt: &SyntaxContext) -> Result<(), Self::Error> {
-        rustc_span::hygiene::raw_encode_syntax_context(*ctxt, &self.hygiene_ctxt, self)
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SyntaxContext {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s)
     }
 }
 
-impl<'a, 'tcx> SpecializedEncoder<ExpnId> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, expn: &ExpnId) -> Result<(), Self::Error> {
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
         rustc_span::hygiene::raw_encode_expn_id(
-            *expn,
-            &self.hygiene_ctxt,
+            *self,
+            &s.hygiene_ctxt,
             ExpnDataEncodeMode::Metadata,
-            self,
+            s,
         )
     }
 }
 
-impl<'a, 'tcx> SpecializedEncoder<DefIndex> for EncodeContext<'a, 'tcx> {
-    #[inline]
-    fn specialized_encode(&mut self, def_index: &DefIndex) -> Result<(), Self::Error> {
-        self.emit_u32(def_index.as_u32())
-    }
-}
-
-impl<'a, 'tcx> SpecializedEncoder<Span> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
-        if span.is_dummy() {
-            return TAG_INVALID_SPAN.encode(self);
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        if self.is_dummy() {
+            return TAG_INVALID_SPAN.encode(s);
         }
 
-        let span = span.data();
+        let span = self.data();
 
         // The Span infrastructure should make sure that this invariant holds:
         debug_assert!(span.lo <= span.hi);
 
-        if !self.source_file_cache.0.contains(span.lo) {
-            let source_map = self.tcx.sess.source_map();
+        if !s.source_file_cache.0.contains(span.lo) {
+            let source_map = s.tcx.sess.source_map();
             let source_file_index = source_map.lookup_source_file_idx(span.lo);
-            self.source_file_cache =
+            s.source_file_cache =
                 (source_map.files()[source_file_index].clone(), source_file_index);
         }
 
-        if !self.source_file_cache.0.contains(span.hi) {
+        if !s.source_file_cache.0.contains(span.hi) {
             // Unfortunately, macro expansion still sometimes generates Spans
             // that malformed in this way.
-            return TAG_INVALID_SPAN.encode(self);
+            return TAG_INVALID_SPAN.encode(s);
         }
 
-        let source_files = self.required_source_files.as_mut().expect("Already encoded SourceMap!");
+        let source_files = s.required_source_files.as_mut().expect("Already encoded SourceMap!");
         // Record the fact that we need to encode the data for this `SourceFile`
-        source_files.insert(self.source_file_cache.1);
+        source_files.insert(s.source_file_cache.1);
 
         // There are two possible cases here:
         // 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the
@@ -218,7 +205,7 @@ impl<'a, 'tcx> SpecializedEncoder<Span> for EncodeContext<'a, 'tcx> {
         // if we're a proc-macro crate.
         // This allows us to avoid loading the dependencies of proc-macro crates: all of
         // the information we need to decode `Span`s is stored in the proc-macro crate.
-        let (tag, lo, hi) = if self.source_file_cache.0.is_imported() && !self.is_proc_macro {
+        let (tag, lo, hi) = if s.source_file_cache.0.is_imported() && !s.is_proc_macro {
             // To simplify deserialization, we 'rebase' this span onto the crate it originally came from
             // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values
             // are relative to the source map information for the 'foreign' crate whose CrateNum
@@ -230,26 +217,26 @@ impl<'a, 'tcx> SpecializedEncoder<Span> for EncodeContext<'a, 'tcx> {
             // Span that can be used without any additional trouble.
             let external_start_pos = {
                 // Introduce a new scope so that we drop the 'lock()' temporary
-                match &*self.source_file_cache.0.external_src.lock() {
+                match &*s.source_file_cache.0.external_src.lock() {
                     ExternalSource::Foreign { original_start_pos, .. } => *original_start_pos,
                     src => panic!("Unexpected external source {:?}", src),
                 }
             };
-            let lo = (span.lo - self.source_file_cache.0.start_pos) + external_start_pos;
-            let hi = (span.hi - self.source_file_cache.0.start_pos) + external_start_pos;
+            let lo = (span.lo - s.source_file_cache.0.start_pos) + external_start_pos;
+            let hi = (span.hi - s.source_file_cache.0.start_pos) + external_start_pos;
 
             (TAG_VALID_SPAN_FOREIGN, lo, hi)
         } else {
             (TAG_VALID_SPAN_LOCAL, span.lo, span.hi)
         };
 
-        tag.encode(self)?;
-        lo.encode(self)?;
+        tag.encode(s)?;
+        lo.encode(s)?;
 
         // Encode length which is usually less than span.hi and profits more
         // from the variable-length integer encoding that we use.
         let len = hi - lo;
-        len.encode(self)?;
+        len.encode(s)?;
 
         // Don't serialize any `SyntaxContext`s from a proc-macro crate,
         // since we don't load proc-macro dependencies during serialization.
@@ -282,101 +269,85 @@ impl<'a, 'tcx> SpecializedEncoder<Span> for EncodeContext<'a, 'tcx> {
         // IMPORTANT: If this is ever changed, be sure to update
         // `rustc_span::hygiene::raw_encode_expn_id` to handle
         // encoding `ExpnData` for proc-macro crates.
-        if self.is_proc_macro {
-            SyntaxContext::root().encode(self)?;
+        if s.is_proc_macro {
+            SyntaxContext::root().encode(s)?;
         } else {
-            span.ctxt.encode(self)?;
+            span.ctxt.encode(s)?;
         }
 
         if tag == TAG_VALID_SPAN_FOREIGN {
-            // This needs to be two lines to avoid holding the `self.source_file_cache`
-            // while calling `cnum.encode(self)`
-            let cnum = self.source_file_cache.0.cnum;
-            cnum.encode(self)?;
+            // This needs to be two lines to avoid holding the `s.source_file_cache`
+            // while calling `cnum.encode(s)`
+            let cnum = s.source_file_cache.0.cnum;
+            cnum.encode(s)?;
         }
 
         Ok(())
     }
 }
 
-impl<'a, 'tcx> SpecializedEncoder<LocalDefId> for EncodeContext<'a, 'tcx> {
-    #[inline]
-    fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> {
-        self.specialized_encode(&def_id.to_def_id())
+impl<'a, 'tcx> FingerprintEncoder for EncodeContext<'a, 'tcx> {
+    fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
+        f.encode_opaque(&mut self.opaque)
     }
 }
 
-impl<'a, 'b, 'c, 'tcx> SpecializedEncoder<&'a ty::TyS<'b>> for EncodeContext<'c, 'tcx>
-where
-    &'a ty::TyS<'b>: UseSpecializedEncodable,
-{
-    fn specialized_encode(&mut self, ty: &&'a ty::TyS<'b>) -> Result<(), Self::Error> {
-        debug_assert!(self.tcx.lift(ty).is_some());
-        let ty = unsafe { std::mem::transmute::<&&'a ty::TyS<'b>, &&'tcx ty::TyS<'tcx>>(ty) };
-        ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands)
+impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
+    const CLEAR_CROSS_CRATE: bool = true;
+
+    fn position(&self) -> usize {
+        self.opaque.position()
     }
-}
 
-impl<'a, 'b, 'tcx> SpecializedEncoder<ty::Predicate<'b>> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> {
-        debug_assert!(self.tcx.lift(predicate).is_some());
-        let predicate =
-            unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) };
-        ty_codec::encode_with_shorthand(self, predicate, |encoder| {
-            &mut encoder.predicate_shorthands
-        })
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
     }
-}
 
-impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
-        let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
-        index.encode(self)
+    fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
+        &mut self.type_shorthands
     }
-}
 
-impl<'a, 'tcx> SpecializedEncoder<Fingerprint> for EncodeContext<'a, 'tcx> {
-    fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
-        f.encode_opaque(&mut self.opaque)
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<rustc_middle::ty::Predicate<'tcx>, usize> {
+        &mut self.predicate_shorthands
     }
-}
 
-impl<'a, 'tcx, T> SpecializedEncoder<mir::ClearCrossCrate<T>> for EncodeContext<'a, 'tcx>
-where
-    mir::ClearCrossCrate<T>: UseSpecializedEncodable,
-{
-    fn specialized_encode(&mut self, _: &mir::ClearCrossCrate<T>) -> Result<(), Self::Error> {
-        Ok(())
+    fn encode_alloc_id(
+        &mut self,
+        alloc_id: &rustc_middle::mir::interpret::AllocId,
+    ) -> Result<(), Self::Error> {
+        let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
+
+        index.encode(self)
     }
 }
 
-impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
-    fn position(&self) -> usize {
-        self.opaque.position()
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        (**self).encode(s)
     }
 }
 
 /// Helper trait to allow overloading `EncodeContext::lazy` for iterators.
-trait EncodeContentsForLazy<T: ?Sized + LazyMeta> {
+trait EncodeContentsForLazy<'a, 'tcx, T: ?Sized + LazyMeta> {
     fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> T::Meta;
 }
 
-impl<T: Encodable> EncodeContentsForLazy<T> for &T {
+impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, T> for &T {
     fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
         self.encode(ecx).unwrap()
     }
 }
 
-impl<T: Encodable> EncodeContentsForLazy<T> for T {
+impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, T> for T {
     fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
         self.encode(ecx).unwrap()
     }
 }
 
-impl<I, T: Encodable> EncodeContentsForLazy<[T]> for I
+impl<'a, 'tcx, I, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, [T]> for I
 where
     I: IntoIterator,
-    I::Item: EncodeContentsForLazy<T>,
+    I::Item: EncodeContentsForLazy<'a, 'tcx, T>,
 {
     fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> usize {
         self.into_iter().map(|value| value.encode_contents_for_lazy(ecx)).count()
@@ -421,7 +392,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.emit_usize(distance)
     }
 
-    fn lazy<T: ?Sized + LazyMeta>(&mut self, value: impl EncodeContentsForLazy<T>) -> Lazy<T> {
+    fn lazy<T: ?Sized + LazyMeta>(
+        &mut self,
+        value: impl EncodeContentsForLazy<'a, 'tcx, T>,
+    ) -> Lazy<T> {
         let pos = NonZeroUsize::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index 1c287be9f6b..b15c20e515f 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -26,8 +26,10 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
 
+use decoder::DecodeContext;
 pub use decoder::{provide, provide_extern};
 crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
+use encoder::EncodeContext;
 use rustc_span::hygiene::SyntaxContextData;
 
 mod decoder;
@@ -141,9 +143,6 @@ impl<T: ?Sized + LazyMeta> Clone for Lazy<T> {
     }
 }
 
-impl<T: ?Sized + LazyMeta> rustc_serialize::UseSpecializedEncodable for Lazy<T> {}
-impl<T: ?Sized + LazyMeta> rustc_serialize::UseSpecializedDecodable for Lazy<T> {}
-
 /// Encoding / decoding state for `Lazy`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum LazyState {
@@ -172,7 +171,7 @@ macro_rules! Lazy {
 type SyntaxContextTable = Lazy<Table<u32, Lazy<SyntaxContextData>>>;
 type ExpnDataTable = Lazy<Table<u32, Lazy<ExpnData>>>;
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(MetadataEncodable, MetadataDecodable)]
 crate struct CrateRoot<'tcx> {
     name: Symbol,
     triple: TargetTriple,
@@ -221,7 +220,7 @@ crate struct CrateRoot<'tcx> {
     symbol_mangling_version: SymbolManglingVersion,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 crate struct CrateDep {
     pub name: Symbol,
     pub hash: Svh,
@@ -230,7 +229,7 @@ crate struct CrateDep {
     pub extra_filename: String,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(MetadataEncodable, MetadataDecodable)]
 crate struct TraitImpls {
     trait_id: (u32, DefIndex),
     impls: Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>,
@@ -239,7 +238,7 @@ crate struct TraitImpls {
 /// Define `LazyTables` and `TableBuilders` at the same time.
 macro_rules! define_tables {
     ($($name:ident: Table<DefIndex, $T:ty>),+ $(,)?) => {
-        #[derive(RustcEncodable, RustcDecodable)]
+        #[derive(MetadataEncodable, MetadataDecodable)]
         crate struct LazyTables<'tcx> {
             $($name: Lazy!(Table<DefIndex, $T>)),+
         }
@@ -288,7 +287,7 @@ define_tables! {
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
 enum EntryKind {
     AnonConst(mir::ConstQualifs, Lazy<RenderedConst>),
     Const(mir::ConstQualifs, Lazy<RenderedConst>),
@@ -324,23 +323,23 @@ enum EntryKind {
 
 /// Contains a constant which has been rendered to a String.
 /// Used by rustdoc.
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 struct RenderedConst(String);
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(MetadataEncodable, MetadataDecodable)]
 struct ModData {
     reexports: Lazy<[Export<hir::HirId>]>,
     expansion: ExpnId,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(MetadataEncodable, MetadataDecodable)]
 struct FnData {
     asyncness: hir::IsAsync,
     constness: hir::Constness,
     param_names: Lazy<[Ident]>,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(TyEncodable, TyDecodable)]
 struct VariantData {
     ctor_kind: CtorKind,
     discr: ty::VariantDiscr,
@@ -349,7 +348,7 @@ struct VariantData {
     is_non_exhaustive: bool,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(TyEncodable, TyDecodable)]
 struct TraitData {
     unsafety: hir::Unsafety,
     paren_sugar: bool,
@@ -358,7 +357,7 @@ struct TraitData {
     specialization_kind: ty::trait_def::TraitSpecializationKind,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(TyEncodable, TyDecodable)]
 struct ImplData {
     polarity: ty::ImplPolarity,
     defaultness: hir::Defaultness,
@@ -372,7 +371,7 @@ struct ImplData {
 /// Describes whether the container of an associated item
 /// is a trait or an impl and whether, in a trait, it has
 /// a default, or an in impl, whether it's marked "default".
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, TyEncodable, TyDecodable)]
 enum AssocContainer {
     TraitRequired,
     TraitWithDefault,
@@ -404,14 +403,14 @@ impl AssocContainer {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(MetadataEncodable, MetadataDecodable)]
 struct AssocFnData {
     fn_data: FnData,
     container: AssocContainer,
     has_self: bool,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(TyEncodable, TyDecodable)]
 struct GeneratorData<'tcx> {
     layout: mir::GeneratorLayout<'tcx>,
 }
diff --git a/src/librustc_metadata/rmeta/table.rs b/src/librustc_metadata/rmeta/table.rs
index e1d0a0dbf2f..728ab0015d1 100644
--- a/src/librustc_metadata/rmeta/table.rs
+++ b/src/librustc_metadata/rmeta/table.rs
@@ -2,7 +2,7 @@ use crate::rmeta::*;
 
 use log::debug;
 use rustc_index::vec::Idx;
-use rustc_serialize::{opaque::Encoder, Encodable};
+use rustc_serialize::opaque::Encoder;
 use std::convert::TryInto;
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
@@ -78,7 +78,7 @@ impl FixedSizeEncoding for u32 {
 // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
 // generic `Lazy<T>` impl, but in the general case we might not need / want to
 // fit every `usize` in `u32`.
-impl<T: Encodable> FixedSizeEncoding for Option<Lazy<T>> {
+impl<T> FixedSizeEncoding for Option<Lazy<T>> {
     fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN);
 
     fn from_bytes(b: &[u8]) -> Self {
@@ -93,7 +93,7 @@ impl<T: Encodable> FixedSizeEncoding for Option<Lazy<T>> {
     }
 }
 
-impl<T: Encodable> FixedSizeEncoding for Option<Lazy<[T]>> {
+impl<T> FixedSizeEncoding for Option<Lazy<[T]>> {
     fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN * 2);
 
     fn from_bytes(b: &[u8]) -> Self {
diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs
index f2259e5e9f8..99889c74da0 100644
--- a/src/librustc_middle/arena.rs
+++ b/src/librustc_middle/arena.rs
@@ -11,13 +11,11 @@
 macro_rules! arena_types {
     ($macro:path, $args:tt, $tcx:lifetime) => (
         $macro!($args, [
-            [] layouts: rustc_target::abi::Layout, rustc_target::abi::Layout;
+            [] layouts: rustc_target::abi::Layout,
             // AdtDef are interned and compared by address
-            [] adt_def: rustc_middle::ty::AdtDef, rustc_middle::ty::AdtDef;
-            [] steal_mir:
-                rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>,
-                rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>;
-            [decode] mir: rustc_middle::mir::Body<$tcx>, rustc_middle::mir::Body<'_x>;
+            [] adt_def: rustc_middle::ty::AdtDef,
+            [] steal_mir: rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>,
+            [decode] mir: rustc_middle::mir::Body<$tcx>,
             [] steal_promoted:
                 rustc_middle::ty::steal::Steal<
                     rustc_index::vec::IndexVec<
@@ -25,127 +23,86 @@ macro_rules! arena_types {
                         rustc_middle::mir::Body<$tcx>
                     >
                 >,
-                rustc_middle::ty::steal::Steal<
-                    rustc_index::vec::IndexVec<
-                        rustc_middle::mir::Promoted,
-                        rustc_middle::mir::Body<$tcx>
-                    >
-                >;
             [decode] promoted:
                 rustc_index::vec::IndexVec<
                     rustc_middle::mir::Promoted,
                     rustc_middle::mir::Body<$tcx>
                 >,
-                rustc_index::vec::IndexVec<
-                    rustc_middle::mir::Promoted,
-                    rustc_middle::mir::Body<'_x>
-                >;
-            [decode] typeck_results: rustc_middle::ty::TypeckResults<$tcx>, rustc_middle::ty::TypeckResults<'_x>;
+            [decode] typeck_results: rustc_middle::ty::TypeckResults<$tcx>,
             [decode] borrowck_result:
                 rustc_middle::mir::BorrowCheckResult<$tcx>,
-                rustc_middle::mir::BorrowCheckResult<'_x>;
-            [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, rustc_middle::mir::UnsafetyCheckResult;
-            [] const_allocs: rustc_middle::mir::interpret::Allocation, rustc_middle::mir::interpret::Allocation;
+            [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
+            [] const_allocs: rustc_middle::mir::interpret::Allocation,
             // Required for the incremental on-disk cache
-            [few, decode] mir_keys: rustc_hir::def_id::DefIdSet, rustc_hir::def_id::DefIdSet;
-            [] region_scope_tree: rustc_middle::middle::region::ScopeTree, rustc_middle::middle::region::ScopeTree;
+            [few] mir_keys: rustc_hir::def_id::DefIdSet,
+            [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
             [] dropck_outlives:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx,
                         rustc_middle::traits::query::DropckOutlivesResult<'tcx>
                     >
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y,
-                        rustc_middle::traits::query::DropckOutlivesResult<'_z>
-                    >
-                >;
             [] normalize_projection_ty:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx,
                         rustc_middle::traits::query::NormalizationResult<'tcx>
                     >
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y,
-                        rustc_middle::traits::query::NormalizationResult<'_z>
-                    >
-                >;
             [] implied_outlives_bounds:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx,
                         Vec<rustc_middle::traits::query::OutlivesBound<'tcx>>
                     >
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y,
-                        Vec<rustc_middle::traits::query::OutlivesBound<'_z>>
-                    >
-                >;
             [] type_op_subtype:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx, ()>
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y, ()>
-                >;
             [] type_op_normalize_poly_fn_sig:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::PolyFnSig<'tcx>>
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y, rustc_middle::ty::PolyFnSig<'_z>>
-                >;
             [] type_op_normalize_fn_sig:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>>
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y, rustc_middle::ty::FnSig<'_z>>
-                >;
             [] type_op_normalize_predicate:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>>
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y, rustc_middle::ty::Predicate<'_z>>
-                >;
             [] type_op_normalize_ty:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
                 >,
-                rustc_middle::infer::canonical::Canonical<'_x,
-                    rustc_middle::infer::canonical::QueryResponse<'_y, &'_z rustc_middle::ty::TyS<'_w>>
-                >;
-            [few] all_traits: Vec<rustc_hir::def_id::DefId>, Vec<rustc_hir::def_id::DefId>;
-            [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, rustc_middle::middle::privacy::AccessLevels;
-            [few] foreign_module: rustc_middle::middle::cstore::ForeignModule, rustc_middle::middle::cstore::ForeignModule;
-            [few] foreign_modules: Vec<rustc_middle::middle::cstore::ForeignModule>, Vec<rustc_middle::middle::cstore::ForeignModule>;
-            [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>;
-            [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, rustc_middle::traits::ObjectSafetyViolation;
-            [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, rustc_middle::mir::mono::CodegenUnit<'_x>;
-            [] attribute: rustc_ast::ast::Attribute, rustc_ast::ast::Attribute;
-            [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>, rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>;
-            [] hir_id_set: rustc_hir::HirIdSet, rustc_hir::HirIdSet;
+            [few] all_traits: Vec<rustc_hir::def_id::DefId>,
+            [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
+            [few] foreign_module: rustc_middle::middle::cstore::ForeignModule,
+            [few] foreign_modules: Vec<rustc_middle::middle::cstore::ForeignModule>,
+            [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
+            [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
+            [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>,
+            [] attribute: rustc_ast::ast::Attribute,
+            [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
+            [] hir_id_set: rustc_hir::HirIdSet,
 
             // Interned types
-            [] tys: rustc_middle::ty::TyS<$tcx>, rustc_middle::ty::TyS<'_x>;
-            [] predicates: rustc_middle::ty::PredicateInner<$tcx>, rustc_middle::ty::PredicateInner<'_x>;
+            [] tys: rustc_middle::ty::TyS<$tcx>,
+            [] predicates: rustc_middle::ty::PredicateInner<$tcx>,
 
             // HIR query types
-            [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, rustc_middle::hir::map::IndexedHir<'_x>;
-            [few] hir_definitions: rustc_hir::definitions::Definitions, rustc_hir::definitions::Definitions;
-            [] hir_owner: rustc_middle::hir::Owner<$tcx>, rustc_middle::hir::Owner<'_x>;
-            [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, rustc_middle::hir::OwnerNodes<'_x>;
+            [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>,
+            [few] hir_definitions: rustc_hir::definitions::Definitions,
+            [] hir_owner: rustc_middle::hir::Owner<$tcx>,
+            [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
 
             // Note that this deliberately duplicates items in the `rustc_hir::arena`,
             // since we need to allocate this type on both the `rustc_hir` arena
             // (during lowering) and the `librustc_middle` arena (for decoding MIR)
-            [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, rustc_ast::ast::InlineAsmTemplatePiece;
+            [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece,
 
             // This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
-            [decode] span: rustc_span::Span, rustc_span::Span;
-            [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>;
+            [decode] span: rustc_span::Span,
+            [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
         ], $tcx);
     )
 }
diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/src/librustc_middle/dep_graph/dep_node.rs
index 98eed4045a3..a61b9af9bac 100644
--- a/src/librustc_middle/dep_graph/dep_node.rs
+++ b/src/librustc_middle/dep_graph/dep_node.rs
@@ -110,8 +110,7 @@ macro_rules! define_dep_nodes {
         $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
       ,)*
     ) => (
-        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
-                 RustcEncodable, RustcDecodable)]
+        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
         #[allow(non_camel_case_types)]
         pub enum DepKind {
             $($variant),*
diff --git a/src/librustc_middle/hir/exports.rs b/src/librustc_middle/hir/exports.rs
index af48c9e94ff..be9e38aca65 100644
--- a/src/librustc_middle/hir/exports.rs
+++ b/src/librustc_middle/hir/exports.rs
@@ -13,7 +13,7 @@ use std::fmt::Debug;
 /// within.
 pub type ExportMap<Id> = FxHashMap<LocalDefId, Vec<Export<Id>>>;
 
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct Export<Id> {
     /// The name of the target.
     pub ident: Ident,
diff --git a/src/librustc_middle/hir/place.rs b/src/librustc_middle/hir/place.rs
index d85165bcccf..bcb56fae170 100644
--- a/src/librustc_middle/hir/place.rs
+++ b/src/librustc_middle/hir/place.rs
@@ -4,7 +4,7 @@ use crate::ty::Ty;
 use rustc_hir::HirId;
 use rustc_target::abi::VariantIdx;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub enum PlaceBase {
     /// A temporary variable
     Rvalue,
@@ -16,7 +16,7 @@ pub enum PlaceBase {
     Upvar(ty::UpvarId),
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub enum ProjectionKind {
     /// A dereference of a pointer, reference or `Box<T>` of the given type
     Deref,
@@ -36,7 +36,7 @@ pub enum ProjectionKind {
     Subslice,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub struct Projection<'tcx> {
     /// Type after the projection is being applied.
     pub ty: Ty<'tcx>,
@@ -48,7 +48,7 @@ pub struct Projection<'tcx> {
 /// A `Place` represents how a value is located in memory.
 ///
 /// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub struct Place<'tcx> {
     /// The type of the `PlaceBase`
     pub base_ty: Ty<'tcx>,
@@ -61,7 +61,7 @@ pub struct Place<'tcx> {
 /// A `PlaceWithHirId` represents how a value is located in memory.
 ///
 /// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub struct PlaceWithHirId<'tcx> {
     /// `HirId` of the expression or pattern producing this value.
     pub hir_id: HirId,
diff --git a/src/librustc_middle/infer/canonical.rs b/src/librustc_middle/infer/canonical.rs
index 9433d282ad2..1e15ae49a0c 100644
--- a/src/librustc_middle/infer/canonical.rs
+++ b/src/librustc_middle/infer/canonical.rs
@@ -26,14 +26,13 @@ use crate::ty::subst::GenericArg;
 use crate::ty::{self, BoundVar, List, Region, TyCtxt};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
-use rustc_serialize::UseSpecializedDecodable;
 use smallvec::SmallVec;
 use std::ops::Index;
 
 /// A "canonicalized" type `V` is one where all free inference
 /// variables have been rewritten to "canonical vars". These are
 /// numbered starting from 0 in order of first appearance.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub struct Canonical<'tcx, V> {
     pub max_universe: ty::UniverseIndex,
@@ -43,8 +42,6 @@ pub struct Canonical<'tcx, V> {
 
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>;
 
-impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {}
-
 /// A set of values corresponding to the canonical variables from some
 /// `Canonical`. You can give these values to
 /// `canonical_value.substitute` to substitute them into the canonical
@@ -54,7 +51,7 @@ impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {}
 /// vectors with the original values that were replaced by canonical
 /// variables. You will need to supply it later to instantiate the
 /// canonicalized query response.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub struct CanonicalVarValues<'tcx> {
     pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
@@ -90,7 +87,7 @@ impl Default for OriginalQueryValues<'tcx> {
 /// canonical value. This is sufficient information for code to create
 /// a copy of the canonical value in some other inference context,
 /// with fresh inference variables replacing the canonical values.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)]
 pub struct CanonicalVarInfo {
     pub kind: CanonicalVarKind,
 }
@@ -115,7 +112,7 @@ impl CanonicalVarInfo {
 /// Describes the "kind" of the canonical variable. This is a "kind"
 /// in the type-theory sense of the term -- i.e., a "meta" type system
 /// that analyzes type-like values.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)]
 pub enum CanonicalVarKind {
     /// Some kind of type inference variable.
     Ty(CanonicalTyVarKind),
@@ -160,7 +157,7 @@ impl CanonicalVarKind {
 /// 22.) can only be instantiated with integral/float types (e.g.,
 /// usize or f32). In order to faithfully reproduce a type, we need to
 /// know what set of types a given type variable can be unified with.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)]
 pub enum CanonicalTyVarKind {
     /// General type variable `?T` that can be unified with arbitrary types.
     General(ty::UniverseIndex),
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/middle/codegen_fn_attrs.rs b/src/librustc_middle/middle/codegen_fn_attrs.rs
index d2749f8529b..62a6198b9b4 100644
--- a/src/librustc_middle/middle/codegen_fn_attrs.rs
+++ b/src/librustc_middle/middle/codegen_fn_attrs.rs
@@ -3,7 +3,7 @@ use rustc_attr::{InlineAttr, OptimizeAttr};
 use rustc_session::config::SanitizerSet;
 use rustc_span::symbol::Symbol;
 
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct CodegenFnAttrs {
     pub flags: CodegenFnAttrFlags,
     /// Parsed representation of the `#[inline]` attribute
@@ -37,7 +37,7 @@ pub struct CodegenFnAttrs {
 }
 
 bitflags! {
-    #[derive(RustcEncodable, RustcDecodable, HashStable)]
+    #[derive(TyEncodable, TyDecodable, HashStable)]
     pub struct CodegenFnAttrFlags: u32 {
         /// `#[cold]`: a hint to LLVM that this function, when called, is never on
         /// the hot path.
diff --git a/src/librustc_middle/middle/cstore.rs b/src/librustc_middle/middle/cstore.rs
index 0a34c06adf0..6a8f6c3e202 100644
--- a/src/librustc_middle/middle/cstore.rs
+++ b/src/librustc_middle/middle/cstore.rs
@@ -25,7 +25,7 @@ use std::path::{Path, PathBuf};
 
 /// Where a crate came from on the local filesystem. One of these three options
 /// must be non-None.
-#[derive(PartialEq, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Clone, Debug, HashStable, Encodable, Decodable)]
 pub struct CrateSource {
     pub dylib: Option<(PathBuf, PathKind)>,
     pub rlib: Option<(PathBuf, PathKind)>,
@@ -38,7 +38,7 @@ impl CrateSource {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
+#[derive(Encodable, Decodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
 #[derive(HashStable)]
 pub enum CrateDepKind {
     /// A dependency that is only used for its macros.
@@ -60,7 +60,7 @@ impl CrateDepKind {
     }
 }
 
-#[derive(PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
 pub enum LibSource {
     Some(PathBuf),
     MetadataOnly,
@@ -80,13 +80,13 @@ impl LibSource {
     }
 }
 
-#[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable)]
 pub enum LinkagePreference {
     RequireDynamic,
     RequireStatic,
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
 pub struct NativeLib {
     pub kind: NativeLibKind,
     pub name: Option<Symbol>,
@@ -95,7 +95,7 @@ pub struct NativeLib {
     pub wasm_import_module: Option<Symbol>,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct ForeignModule {
     pub foreign_items: Vec<DefId>,
     pub def_id: DefId,
@@ -145,7 +145,7 @@ pub enum ExternCrateSource {
     Path,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 pub struct EncodedMetadata {
     pub raw_data: Vec<u8>,
 }
diff --git a/src/librustc_middle/middle/dependency_format.rs b/src/librustc_middle/middle/dependency_format.rs
index 16ce315368a..e079843bfbc 100644
--- a/src/librustc_middle/middle/dependency_format.rs
+++ b/src/librustc_middle/middle/dependency_format.rs
@@ -19,7 +19,7 @@ pub type DependencyList = Vec<Linkage>;
 /// This is local to the tcx, and is generally relevant to one session.
 pub type Dependencies = Vec<(CrateType, DependencyList)>;
 
-#[derive(Copy, Clone, PartialEq, Debug, HashStable, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Encodable, Decodable)]
 pub enum Linkage {
     NotLinked,
     IncludedFromDylib,
diff --git a/src/librustc_middle/middle/exported_symbols.rs b/src/librustc_middle/middle/exported_symbols.rs
index 569af70c5b5..276e45ce99b 100644
--- a/src/librustc_middle/middle/exported_symbols.rs
+++ b/src/librustc_middle/middle/exported_symbols.rs
@@ -8,7 +8,7 @@ use rustc_macros::HashStable;
 /// kind of crate, including cdylibs which export very few things.
 /// `Rust` will only be exported if the crate produced is a Rust
 /// dylib.
-#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub enum SymbolExportLevel {
     C,
     Rust,
@@ -21,7 +21,7 @@ impl SymbolExportLevel {
     }
 }
 
-#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub enum ExportedSymbol<'tcx> {
     NonGeneric(DefId),
     Generic(DefId, SubstsRef<'tcx>),
diff --git a/src/librustc_middle/middle/region.rs b/src/librustc_middle/middle/region.rs
index 943a065a8b5..4c6ac820604 100644
--- a/src/librustc_middle/middle/region.rs
+++ b/src/librustc_middle/middle/region.rs
@@ -80,7 +80,7 @@ use std::fmt;
 // placate the same deriving in `ty::FreeRegion`, but we may want to
 // actually attach a more meaningful ordering to scopes than the one
 // generated via deriving here.
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct Scope {
     pub id: hir::ItemLocalId,
@@ -104,7 +104,7 @@ impl fmt::Debug for Scope {
     }
 }
 
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum ScopeData {
     Node,
@@ -324,7 +324,7 @@ pub struct ScopeTree {
     pub body_expr_count: FxHashMap<hir::BodyId, usize>,
 }
 
-#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct YieldData {
     /// The `Span` of the yield.
     pub span: Span,
diff --git a/src/librustc_middle/middle/resolve_lifetime.rs b/src/librustc_middle/middle/resolve_lifetime.rs
index c21ba1b3bd2..3d0144e9c8a 100644
--- a/src/librustc_middle/middle/resolve_lifetime.rs
+++ b/src/librustc_middle/middle/resolve_lifetime.rs
@@ -11,7 +11,7 @@ use rustc_macros::HashStable;
 /// The origin of a named lifetime definition.
 ///
 /// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum LifetimeDefOrigin {
     // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>`
     ExplicitOrElided,
@@ -35,7 +35,7 @@ impl LifetimeDefOrigin {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum Region {
     Static,
     EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin),
@@ -47,7 +47,7 @@ pub enum Region {
 /// A set containing, at most, one known element.
 /// If two distinct values are inserted into a set, then it
 /// becomes `Many`, which can be used to detect ambiguities.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum Set1<T> {
     Empty,
     One(T),
diff --git a/src/librustc_middle/mir/interpret/allocation.rs b/src/librustc_middle/mir/interpret/allocation.rs
index dd4fc7adff1..bee8d13c762 100644
--- a/src/librustc_middle/mir/interpret/allocation.rs
+++ b/src/librustc_middle/mir/interpret/allocation.rs
@@ -14,7 +14,7 @@ use super::{
     UninitBytesAccess,
 };
 
-#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct Allocation<Tag = (), Extra = ()> {
     /// The actual bytes of the allocation.
@@ -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]
     }
 
@@ -172,8 +172,6 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
     }
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Allocation {}
-
 /// Byte accessors.
 impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// Just a small local helper function to avoid a bit of code repetition.
@@ -194,7 +192,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 +242,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 +300,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 +359,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 +592,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 +634,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,
@@ -666,7 +664,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
 }
 
 /// Relocations.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 pub struct Relocations<Tag = (), Id = AllocId>(SortedMap<Size, (Tag, Id)>);
 
 impl<Tag, Id> Relocations<Tag, Id> {
@@ -747,7 +745,7 @@ type Block = u64;
 
 /// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte
 /// is initialized. If it is `false` the byte is uninitialized.
-#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct InitMask {
     blocks: Vec<Block>,
diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs
index c904cd83a78..059925088ce 100644
--- a/src/librustc_middle/mir/interpret/error.rs
+++ b/src/librustc_middle/mir/interpret/error.rs
@@ -1,21 +1,17 @@
 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};
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 pub enum ErrorHandled {
     /// Already reported an error for this evaluation, and the compilation is
     /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
@@ -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)
 }
@@ -302,7 +137,7 @@ impl fmt::Display for InvalidProgramInfo<'_> {
 }
 
 /// Details of why a pointer had to be in-bounds.
-#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub enum CheckInAllocMsg {
     MemoryAccessTest,
     NullPointerTest,
diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs
index 5e57b60894a..e607da29ce4 100644
--- a/src/librustc_middle/mir/interpret/mod.rs
+++ b/src/librustc_middle/mir/interpret/mod.rs
@@ -108,18 +108,18 @@ use rustc_data_structures::sync::{HashMapExt, Lock};
 use rustc_data_structures::tiny_list::TinyList;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
-use rustc_serialize::{Decodable, Encodable, Encoder};
+use rustc_serialize::{Decodable, Encodable};
 use rustc_target::abi::{Endian, Size};
 
 use crate::mir;
-use crate::ty::codec::TyDecoder;
+use crate::ty::codec::{TyDecoder, TyEncoder};
 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};
@@ -132,7 +132,7 @@ pub use self::pointer::{Pointer, PointerArithmetic};
 /// - A constant
 /// - A static
 /// - A const fn where all arguments (if any) are zero-sized types
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, Lift)]
 pub struct GlobalId<'tcx> {
     /// For a constant or static, the `Instance` of the item itself.
@@ -182,17 +182,14 @@ impl fmt::Display for AllocId {
     }
 }
 
-impl rustc_serialize::UseSpecializedEncodable for AllocId {}
-impl rustc_serialize::UseSpecializedDecodable for AllocId {}
-
-#[derive(RustcDecodable, RustcEncodable)]
+#[derive(TyDecodable, TyEncodable)]
 enum AllocDiscriminant {
     Alloc,
     Fn,
     Static,
 }
 
-pub fn specialized_encode_alloc_id<'tcx, E: Encoder>(
+pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>(
     encoder: &mut E,
     tcx: TyCtxt<'tcx>,
     alloc_id: AllocId,
@@ -333,7 +330,7 @@ impl<'s> AllocDecodingSession<'s> {
         let alloc_id = decoder.with_position(pos, |decoder| {
             match alloc_kind {
                 AllocDiscriminant::Alloc => {
-                    let alloc = <&'tcx Allocation as Decodable>::decode(decoder)?;
+                    let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder)?;
                     // We already have a reserved `AllocId`.
                     let alloc_id = alloc_id.unwrap();
                     trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
@@ -351,7 +348,7 @@ impl<'s> AllocDecodingSession<'s> {
                 AllocDiscriminant::Static => {
                     assert!(alloc_id.is_none());
                     trace!("creating extern static alloc ID");
-                    let did = DefId::decode(decoder)?;
+                    let did = <DefId as Decodable<D>>::decode(decoder)?;
                     trace!("decoded static def-ID: {:?}", did);
                     let alloc_id = decoder.tcx().create_static_alloc(did);
                     Ok(alloc_id)
@@ -369,7 +366,7 @@ impl<'s> AllocDecodingSession<'s> {
 
 /// An allocation in the global (tcx-managed) memory can be either a function pointer,
 /// a static, or a "real" allocation with some data in it.
-#[derive(Debug, Clone, Eq, PartialEq, Hash, RustcDecodable, RustcEncodable, HashStable)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)]
 pub enum GlobalAlloc<'tcx> {
     /// The alloc ID is used as a function pointer.
     Function(Instance<'tcx>),
diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/src/librustc_middle/mir/interpret/pointer.rs
index ccad4f0a135..e3d5a085613 100644
--- a/src/librustc_middle/mir/interpret/pointer.rs
+++ b/src/librustc_middle/mir/interpret/pointer.rs
@@ -87,7 +87,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
 ///
 /// `Pointer` is generic over the `Tag` associated with each pointer,
 /// which is used to do provenance tracking during execution.
-#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
 pub struct Pointer<Tag = ()> {
     pub alloc_id: AllocId,
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..4c47f25105d 100644
--- a/src/librustc_middle/mir/interpret/value.rs
+++ b/src/librustc_middle/mir/interpret/value.rs
@@ -23,7 +23,7 @@ pub struct RawConst<'tcx> {
 
 /// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
 /// array length computations, enum discriminants and the pattern matching logic.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
 pub enum ConstValue<'tcx> {
     /// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
@@ -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
@@ -108,7 +108,7 @@ impl<'tcx> ConstValue<'tcx> {
 /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
 /// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
 /// of a simple value or a pointer into another `Allocation`
-#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
 pub enum Scalar<Tag = ()> {
     /// The raw bytes of a simple value.
@@ -562,7 +562,7 @@ impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
     }
 }
 
-#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable, HashStable, Hash)]
+#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)]
 pub enum ScalarMaybeUninit<Tag = ()> {
     Scalar(Scalar<Tag>),
     Uninit,
diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 3b0c480f6d4..c53d6315682 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -5,6 +5,7 @@
 use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
+use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{Subst, SubstsRef};
@@ -73,7 +74,7 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
 /// The various "big phases" that MIR goes through.
 ///
 /// Warning: ordering of variants is significant.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(HashStable)]
 pub enum MirPhase {
     Build = 0,
@@ -91,7 +92,7 @@ impl MirPhase {
 }
 
 /// The lowered representation of a single function.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)]
 pub struct Body<'tcx> {
     /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock`
     /// that indexes into this vector.
@@ -413,7 +414,7 @@ impl<'tcx> Body<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum Safety {
     Safe,
     /// Unsafe because of a PushUnsafeBlock
@@ -465,9 +466,13 @@ impl<T> ClearCrossCrate<T> {
 const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0;
 const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1;
 
-impl<T: Encodable> rustc_serialize::UseSpecializedEncodable for ClearCrossCrate<T> {
+impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> {
     #[inline]
-    fn default_encode<E: rustc_serialize::Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        if E::CLEAR_CROSS_CRATE {
+            return Ok(());
+        }
+
         match *self {
             ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(e),
             ClearCrossCrate::Set(ref val) => {
@@ -477,12 +482,13 @@ impl<T: Encodable> rustc_serialize::UseSpecializedEncodable for ClearCrossCrate<
         }
     }
 }
-impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<T> {
+impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
     #[inline]
-    fn default_decode<D>(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error>
-    where
-        D: rustc_serialize::Decoder,
-    {
+    fn decode(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error> {
+        if D::CLEAR_CROSS_CRATE {
+            return Ok(ClearCrossCrate::Clear);
+        }
+
         let discr = u8::decode(d)?;
 
         match discr {
@@ -491,7 +497,7 @@ impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<
                 let val = T::decode(d)?;
                 Ok(ClearCrossCrate::Set(val))
             }
-            _ => unreachable!(),
+            tag => Err(d.error(&format!("Invalid tag for ClearCrossCrate: {:?}", tag))),
         }
     }
 }
@@ -501,7 +507,7 @@ impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<
 /// Most passes can work with it as a whole, within a single function.
 // The unofficial Cranelift backend, at least as of #65828, needs `SourceInfo` to implement `Eq` and
 // `Hash`. Please ping @bjorn3 if removing them.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash, HashStable)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct SourceInfo {
     /// The source span for the AST pertaining to this MIR entity.
     pub span: Span,
@@ -521,7 +527,7 @@ impl SourceInfo {
 ///////////////////////////////////////////////////////////////////////////
 // Borrow kinds
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
@@ -632,7 +638,7 @@ pub enum LocalKind {
     ReturnPointer,
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct VarBindingForm<'tcx> {
     /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
     pub binding_mode: ty::BindingMode,
@@ -654,7 +660,7 @@ pub struct VarBindingForm<'tcx> {
     pub pat_span: Span,
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable)]
 pub enum BindingForm<'tcx> {
     /// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
     Var(VarBindingForm<'tcx>),
@@ -665,7 +671,7 @@ pub enum BindingForm<'tcx> {
 }
 
 /// Represents what type of implicit self a function has, if any.
-#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum ImplicitSelfKind {
     /// Represents a `fn x(self);`.
     Imm,
@@ -708,7 +714,7 @@ mod binding_form_impl {
 /// involved in borrow_check errors, e.g., explanations of where the
 /// temporaries come from, when their destructors are run, and/or how
 /// one might revise the code to satisfy the borrow checker's rules.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct BlockTailInfo {
     /// If `true`, then the value resulting from evaluating this tail
     /// expression is ignored by the block's expression context.
@@ -725,7 +731,7 @@ pub struct BlockTailInfo {
 ///
 /// This can be a binding declared by the user, a temporary inserted by the compiler, a function
 /// argument, or the return place.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct LocalDecl<'tcx> {
     /// Whether this is a mutable minding (i.e., `let x` or `let mut x`).
     ///
@@ -857,10 +863,13 @@ pub struct LocalDecl<'tcx> {
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(LocalDecl<'_>, 56);
 
-/// Extra information about a some locals that's used for diagnostics. (Not
-/// used for non-StaticRef temporaries, the return place, or anonymous function
-/// parameters.)
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+/// Extra information about a some locals that's used for diagnostics and for
+/// classifying variables into local variables, statics, etc, which is needed e.g.
+/// for unsafety checking.
+///
+/// Not used for non-StaticRef temporaries, the return place, or anonymous
+/// function parameters.
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub enum LocalInfo<'tcx> {
     /// A user-defined local variable or function parameter
     ///
@@ -1003,7 +1012,7 @@ impl<'tcx> LocalDecl<'tcx> {
 }
 
 /// Debug information pertaining to a user variable.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct VarDebugInfo<'tcx> {
     pub name: Symbol,
 
@@ -1038,7 +1047,7 @@ impl BasicBlock {
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlockData and Terminator
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct BasicBlockData<'tcx> {
     /// List of statements in this block.
     pub statements: Vec<Statement<'tcx>>,
@@ -1061,7 +1070,7 @@ pub struct BasicBlockData<'tcx> {
 }
 
 /// Information about an assertion failure.
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
 pub enum AssertKind<O> {
     BoundsCheck { len: O, index: O },
     Overflow(BinOp, O, O),
@@ -1072,7 +1081,7 @@ pub enum AssertKind<O> {
     ResumedAfterPanic(GeneratorKind),
 }
 
-#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -1317,7 +1326,7 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
 ///////////////////////////////////////////////////////////////////////////
 // Statements
 
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct Statement<'tcx> {
     pub source_info: SourceInfo,
     pub kind: StatementKind<'tcx>,
@@ -1343,7 +1352,7 @@ impl Statement<'_> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub enum StatementKind<'tcx> {
     /// Write the RHS Rvalue to the LHS Place.
     Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
@@ -1396,7 +1405,7 @@ pub enum StatementKind<'tcx> {
 }
 
 /// Describes what kind of retag is to be performed.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, HashStable)]
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, HashStable)]
 pub enum RetagKind {
     /// The initial retag when entering a function.
     FnEntry,
@@ -1409,7 +1418,7 @@ pub enum RetagKind {
 }
 
 /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable, PartialEq)]
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, HashStable, PartialEq)]
 pub enum FakeReadCause {
     /// Inject a fake read of the borrowed input at the end of each guards
     /// code.
@@ -1451,7 +1460,7 @@ pub enum FakeReadCause {
     ForIndex,
 }
 
-#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct LlvmInlineAsm<'tcx> {
     pub asm: hir::LlvmInlineAsmInner,
     pub outputs: Box<[Place<'tcx>]>,
@@ -1496,7 +1505,7 @@ impl Debug for Statement<'_> {
 
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
 pub struct Place<'tcx> {
     pub local: Local,
 
@@ -1504,10 +1513,8 @@ pub struct Place<'tcx> {
     pub projection: &'tcx List<PlaceElem<'tcx>>,
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[derive(RustcEncodable, RustcDecodable, HashStable)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
 pub enum ProjectionElem<V, T> {
     Deref,
     Field(Field, T),
@@ -1732,7 +1739,7 @@ rustc_index::newtype_index! {
     }
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct SourceScopeData {
     pub span: Span,
     pub parent_scope: Option<SourceScope>,
@@ -1742,7 +1749,7 @@ pub struct SourceScopeData {
     pub local_data: ClearCrossCrate<SourceScopeLocalData>,
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct SourceScopeLocalData {
     /// An `HirId` with lint levels equivalent to this scope's lint levels.
     pub lint_root: hir::HirId,
@@ -1755,7 +1762,7 @@ pub struct SourceScopeLocalData {
 
 /// These are values that can appear inside an rvalue. They are intentionally
 /// limited to prevent rvalues from being nested in one another.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub enum Operand<'tcx> {
     /// Copy: The value must be available for use afterwards.
     ///
@@ -1889,7 +1896,7 @@ impl<'tcx> Operand<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 /// Rvalues
 
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
 pub enum Rvalue<'tcx> {
     /// x (either a move or copy, depending on type of x)
     Use(Operand<'tcx>),
@@ -1935,13 +1942,13 @@ pub enum Rvalue<'tcx> {
     Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum CastKind {
     Misc,
     Pointer(PointerCast),
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum AggregateKind<'tcx> {
     /// The type is of the element
     Array(Ty<'tcx>),
@@ -1958,7 +1965,7 @@ pub enum AggregateKind<'tcx> {
     Generator(DefId, SubstsRef<'tcx>, hir::Movability),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum BinOp {
     /// The `+` operator (addition)
     Add,
@@ -2006,7 +2013,7 @@ impl BinOp {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum NullOp {
     /// Returns the size of a value of that type
     SizeOf,
@@ -2014,7 +2021,7 @@ pub enum NullOp {
     Box,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum UnOp {
     /// The `!` operator for logical inversion
     Not,
@@ -2184,7 +2191,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 /// this does not necessarily mean that they are "==" in Rust -- in
 /// particular one must be wary of `NaN`!
 
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub struct Constant<'tcx> {
     pub span: Span,
 
@@ -2245,7 +2252,7 @@ impl Constant<'tcx> {
 /// The first will lead to the constraint `w: &'1 str` (for some
 /// inferred region `'1`). The second will lead to the constraint `w:
 /// &'static str`.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct UserTypeProjections {
     pub contents: Vec<(UserTypeProjection, Span)>,
 }
@@ -2322,7 +2329,7 @@ impl<'tcx> UserTypeProjections {
 /// * `let (x, _): T = ...` -- here, the `projs` vector would contain
 ///   `field[0]` (aka `.0`), indicating that the type of `s` is
 ///   determined by finding the type of the `.0` field from `T`.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq)]
 pub struct UserTypeProjection {
     pub base: UserTypeAnnotationIndex,
     pub projs: Vec<ProjectionKind>,
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index bb204223b60..5081295ab3f 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -242,7 +242,7 @@ pub struct CodegenUnit<'tcx> {
 /// Specifies the linkage type for a `MonoItem`.
 ///
 /// See https://llvm.org/docs/LangRef.html#linkage-types for more details about these variants.
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum Linkage {
     External,
     AvailableExternally,
diff --git a/src/librustc_middle/mir/predecessors.rs b/src/librustc_middle/mir/predecessors.rs
index 7508c023939..b16a1d53fff 100644
--- a/src/librustc_middle/mir/predecessors.rs
+++ b/src/librustc_middle/mir/predecessors.rs
@@ -54,16 +54,16 @@ impl PredecessorCache {
     }
 }
 
-impl serialize::Encodable for PredecessorCache {
+impl<S: serialize::Encoder> serialize::Encodable<S> for PredecessorCache {
     #[inline]
-    fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         serialize::Encodable::encode(&(), s)
     }
 }
 
-impl serialize::Decodable for PredecessorCache {
+impl<D: serialize::Decoder> serialize::Decodable<D> for PredecessorCache {
     #[inline]
-    fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+    fn decode(d: &mut D) -> Result<Self, D::Error> {
         serialize::Decodable::decode(d).map(|_v: ()| Self::new())
     }
 }
diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs
index 6ce5d61fbed..0878e9313d8 100644
--- a/src/librustc_middle/mir/query.rs
+++ b/src/librustc_middle/mir/query.rs
@@ -16,7 +16,7 @@ use std::fmt::{self, Debug};
 
 use super::{Field, SourceInfo};
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub enum UnsafetyViolationKind {
     /// Only permitted in regular `fn`s, prohibited in `const fn`s.
     General,
@@ -35,7 +35,7 @@ pub enum UnsafetyViolationKind {
     UnsafeFnBorrowPacked,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub enum UnsafetyViolationDetails {
     CallToUnsafeFunction,
     UseOfInlineAssembly,
@@ -120,7 +120,7 @@ impl UnsafetyViolationDetails {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub struct UnsafetyViolation {
     pub source_info: SourceInfo,
     pub lint_root: hir::HirId,
@@ -128,7 +128,7 @@ pub struct UnsafetyViolation {
     pub details: UnsafetyViolationDetails,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct UnsafetyCheckResult {
     /// Violations that are propagated *upwards* from this function.
     pub violations: Lrc<[UnsafetyViolation]>,
@@ -145,7 +145,7 @@ rustc_index::newtype_index! {
 }
 
 /// The layout of generator state.
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct GeneratorLayout<'tcx> {
     /// The type of every local stored inside the generator.
     pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>,
@@ -220,7 +220,7 @@ impl Debug for GeneratorLayout<'_> {
     }
 }
 
-#[derive(Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct BorrowCheckResult<'tcx> {
     /// All the opaque types that are restricted to concrete types
     /// by this function. Unlike the value in `TypeckResults`, this has
@@ -235,7 +235,7 @@ pub struct BorrowCheckResult<'tcx> {
 /// Each field corresponds to an implementer of the `Qualif` trait in
 /// `librustc_mir/transform/check_consts/qualifs.rs`. See that file for more information on each
 /// `Qualif`.
-#[derive(Clone, Copy, Debug, Default, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)]
 pub struct ConstQualifs {
     pub has_mut_interior: bool,
     pub needs_drop: bool,
@@ -291,7 +291,7 @@ pub struct ConstQualifs {
 /// `ReEarlyBound`, `ReFree`). We use these because in a query response we
 /// cannot use `ReVar` (which is what we use internally within the rest of the
 /// NLL code).
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct ClosureRegionRequirements<'tcx> {
     /// The number of external regions defined on the closure. In our
     /// example above, it would be 3 -- one for `'static`, then `'1`
@@ -307,7 +307,7 @@ pub struct ClosureRegionRequirements<'tcx> {
 
 /// Indicates an outlives-constraint between a type or between two
 /// free regions declared on the closure.
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct ClosureOutlivesRequirement<'tcx> {
     // This region or type ...
     pub subject: ClosureOutlivesSubject<'tcx>,
@@ -328,7 +328,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
 ///
 /// See also `rustc_mir::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
-#[derive(RustcEncodable, RustcDecodable, HashStable)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
 pub enum ConstraintCategory {
     Return(ReturnConstraint),
     Yield,
@@ -365,7 +365,7 @@ pub enum ConstraintCategory {
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
-#[derive(RustcEncodable, RustcDecodable, HashStable)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
 pub enum ReturnConstraint {
     Normal,
     ClosureUpvar(hir::HirId),
@@ -373,7 +373,7 @@ pub enum ReturnConstraint {
 
 /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
 /// that must outlive some region.
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum ClosureOutlivesSubject<'tcx> {
     /// Subject is a type, typically a type parameter, but could also
     /// be a projection. Indicates a requirement like `T: 'a` being
@@ -398,7 +398,7 @@ pub struct DestructuredConst<'tcx> {
 /// Coverage information summarized from a MIR if instrumented for source code coverage (see
 /// compiler option `-Zinstrument-coverage`). This information is generated by the
 /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct CoverageInfo {
     /// The total number of coverage region counters added to the MIR `Body`.
     pub num_counters: u32,
diff --git a/src/librustc_middle/mir/terminator/mod.rs b/src/librustc_middle/mir/terminator/mod.rs
index 1f5041141d5..0ab78381224 100644
--- a/src/librustc_middle/mir/terminator/mod.rs
+++ b/src/librustc_middle/mir/terminator/mod.rs
@@ -16,7 +16,7 @@ use std::slice;
 
 pub use super::query::*;
 
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
 pub enum TerminatorKind<'tcx> {
     /// Block should have one successor in the graph; we jump there.
     Goto { target: BasicBlock },
@@ -194,7 +194,7 @@ pub enum TerminatorKind<'tcx> {
         destination: Option<BasicBlock>,
     },
 }
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct Terminator<'tcx> {
     pub source_info: SourceInfo,
     pub kind: TerminatorKind<'tcx>,
diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs
index 585f29386a8..ea9c8b7a415 100644
--- a/src/librustc_middle/traits/mod.rs
+++ b/src/librustc_middle/traits/mod.rs
@@ -426,7 +426,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
 /// ### The type parameter `N`
 ///
 /// See explanation on `ImplSourceUserDefinedData`.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub enum ImplSource<'tcx, N> {
     /// ImplSource identifying a particular impl.
     ImplSourceUserDefined(ImplSourceUserDefinedData<'tcx, N>),
@@ -557,14 +557,14 @@ impl<'tcx, N> ImplSource<'tcx, N> {
 /// is `Obligation`, as one might expect. During codegen, however, this
 /// is `()`, because codegen only requires a shallow resolution of an
 /// impl, and nested obligations are satisfied later.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceUserDefinedData<'tcx, N> {
     pub impl_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceGeneratorData<'tcx, N> {
     pub generator_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -573,7 +573,7 @@ pub struct ImplSourceGeneratorData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceClosureData<'tcx, N> {
     pub closure_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -582,18 +582,18 @@ pub struct ImplSourceClosureData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceAutoImplData<N> {
     pub trait_def_id: DefId,
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceBuiltinData<N> {
     pub nested: Vec<N>,
 }
 
-#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceObjectData<'tcx, N> {
     /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
     pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
@@ -606,17 +606,17 @@ pub struct ImplSourceObjectData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceFnPointerData<'tcx, N> {
     pub fn_ty: Ty<'tcx>,
     pub nested: Vec<N>,
 }
 
 // FIXME(@lcnr): This should be  refactored and merged with other builtin vtables.
-#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub struct ImplSourceDiscriminantKindData;
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceTraitAliasData<'tcx, N> {
     pub alias_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
diff --git a/src/librustc_middle/traits/specialization_graph.rs b/src/librustc_middle/traits/specialization_graph.rs
index c9aae898007..969404c68ca 100644
--- a/src/librustc_middle/traits/specialization_graph.rs
+++ b/src/librustc_middle/traits/specialization_graph.rs
@@ -23,7 +23,7 @@ use rustc_span::symbol::Ident;
 ///   parents of a given specializing impl, which is needed for extracting
 ///   default items amongst other things. In the simple "chain" rule, every impl
 ///   has at most one parent.
-#[derive(RustcEncodable, RustcDecodable, HashStable)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
 pub struct Graph {
     /// All impls have a parent; the "root" impls have as their parent the `def_id`
     /// of the trait.
@@ -50,7 +50,7 @@ impl Graph {
 
 /// Children of a given impl, grouped into blanket/non-blanket varieties as is
 /// done in `TraitDef`.
-#[derive(Default, RustcEncodable, RustcDecodable)]
+#[derive(Default, TyEncodable, TyDecodable)]
 pub struct Children {
     // Impls of a trait (or specializations of a given impl). To allow for
     // quicker lookup, the impls are indexed by a simplified version of their
diff --git a/src/librustc_middle/ty/adjustment.rs b/src/librustc_middle/ty/adjustment.rs
index 52ebcd63e7c..0ab07aea426 100644
--- a/src/librustc_middle/ty/adjustment.rs
+++ b/src/librustc_middle/ty/adjustment.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::{DerefMutTraitLangItem, DerefTraitLangItem};
 use rustc_macros::HashStable;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum PointerCast {
     /// Go from a fn-item type to a fn-pointer type.
     ReifyFnPointer,
@@ -76,7 +76,7 @@ pub enum PointerCast {
 ///    At some point, of course, `Box` should move out of the compiler, in which
 ///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
 ///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct Adjustment<'tcx> {
     pub kind: Adjust<'tcx>,
     pub target: Ty<'tcx>,
@@ -91,7 +91,7 @@ impl Adjustment<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub enum Adjust<'tcx> {
     /// Go from ! to any type.
     NeverToAny,
@@ -109,7 +109,7 @@ pub enum Adjust<'tcx> {
 /// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
 /// The target type is `U` in both cases, with the region and mutability
 /// being those shared by both the receiver and the returned reference.
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct OverloadedDeref<'tcx> {
     pub region: ty::Region<'tcx>,
     pub mutbl: hir::Mutability,
@@ -143,13 +143,13 @@ impl<'tcx> OverloadedDeref<'tcx> {
 /// new code via two-phase borrows, so we try to limit where we create two-phase
 /// capable mutable borrows.
 /// See #49434 for tracking.
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum AllowTwoPhase {
     Yes,
     No,
 }
 
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum AutoBorrowMutability {
     Mut { allow_two_phase_borrow: AllowTwoPhase },
     Not,
@@ -164,7 +164,7 @@ impl From<AutoBorrowMutability> for hir::Mutability {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub enum AutoBorrow<'tcx> {
     /// Converts from T to &T.
     Ref(ty::Region<'tcx>, AutoBorrowMutability),
@@ -179,7 +179,7 @@ pub enum AutoBorrow<'tcx> {
 /// This struct can be obtained via the `coerce_impl_info` query.
 /// Demanding this struct also has the side-effect of reporting errors
 /// for inappropriate impls.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct CoerceUnsizedInfo {
     /// If this is a "custom coerce" impl, then what kind of custom
     /// coercion is it? This applies to impls of `CoerceUnsized` for
@@ -188,7 +188,7 @@ pub struct CoerceUnsizedInfo {
     pub custom_kind: Option<CustomCoerceUnsized>,
 }
 
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum CustomCoerceUnsized {
     /// Records the index of the field being coerced.
     Struct(usize),
diff --git a/src/librustc_middle/ty/binding.rs b/src/librustc_middle/ty/binding.rs
index 5ee88115090..3237147c8ba 100644
--- a/src/librustc_middle/ty/binding.rs
+++ b/src/librustc_middle/ty/binding.rs
@@ -2,7 +2,7 @@ use rustc_hir::BindingAnnotation;
 use rustc_hir::BindingAnnotation::*;
 use rustc_hir::Mutability;
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, HashStable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)]
 pub enum BindingMode {
     BindByReference(Mutability),
     BindByValue(Mutability),
diff --git a/src/librustc_middle/ty/cast.rs b/src/librustc_middle/ty/cast.rs
index 31c106cb230..3a3caa55f60 100644
--- a/src/librustc_middle/ty/cast.rs
+++ b/src/librustc_middle/ty/cast.rs
@@ -31,7 +31,7 @@ pub enum CastTy<'tcx> {
 }
 
 /// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum CastKind {
     CoercionCast,
     PtrPtrCast,
diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs
index a7c7b160480..291648869fb 100644
--- a/src/librustc_middle/ty/codec.rs
+++ b/src/librustc_middle/ty/codec.rs
@@ -8,12 +8,15 @@
 
 use crate::arena::ArenaAllocatable;
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
-use crate::mir::{self, interpret::Allocation};
+use crate::mir::{
+    self,
+    interpret::{AllocId, Allocation},
+};
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, List, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::Span;
 use std::convert::{TryFrom, TryInto};
 use std::hash::Hash;
@@ -25,46 +28,75 @@ use std::marker::DiscriminantKind;
 /// This offset is also chosen so that the first byte is never < 0x80.
 pub const SHORTHAND_OFFSET: usize = 0x80;
 
-pub trait EncodableWithShorthand: Clone + Eq + Hash {
-    type Variant: Encodable;
+pub trait EncodableWithShorthand<'tcx, E: TyEncoder<'tcx>>: Copy + Eq + Hash {
+    type Variant: Encodable<E>;
     fn variant(&self) -> &Self::Variant;
 }
 
 #[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx> EncodableWithShorthand for Ty<'tcx> {
+impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> {
     type Variant = ty::TyKind<'tcx>;
     fn variant(&self) -> &Self::Variant {
         &self.kind
     }
 }
 
-impl<'tcx> EncodableWithShorthand for ty::Predicate<'tcx> {
+impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate<'tcx> {
     type Variant = ty::PredicateKind<'tcx>;
     fn variant(&self) -> &Self::Variant {
         self.kind()
     }
 }
 
-pub trait TyEncoder: Encoder {
-    fn position(&self) -> usize;
+pub trait OpaqueEncoder: Encoder {
+    fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder;
+    fn encoder_position(&self) -> usize;
 }
 
-impl TyEncoder for opaque::Encoder {
+impl OpaqueEncoder for rustc_serialize::opaque::Encoder {
+    #[inline]
+    fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder {
+        self
+    }
     #[inline]
-    fn position(&self) -> usize {
+    fn encoder_position(&self) -> usize {
         self.position()
     }
 }
 
+pub trait TyEncoder<'tcx>: Encoder {
+    const CLEAR_CROSS_CRATE: bool;
+
+    fn tcx(&self) -> TyCtxt<'tcx>;
+    fn position(&self) -> usize;
+    fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize>;
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::Predicate<'tcx>, usize>;
+    fn encode_alloc_id(&mut self, alloc_id: &AllocId) -> Result<(), Self::Error>;
+}
+
+/// Trait for decoding to a reference.
+///
+/// This is a separate trait from `Decodable` so that we can implement it for
+/// upstream types, such as `FxHashSet`.
+///
+/// The `TyDecodable` derive macro will use this trait for fields that are
+/// references (and don't use a type alias to hide that).
+///
+/// `Decodable` can still be implemented in cases where `Decodable` is required
+/// by a trait bound.
+pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> {
+    fn decode(d: &mut D) -> Result<&'tcx Self, D::Error>;
+}
+
 /// Encode the given value or a previously cached shorthand.
 pub fn encode_with_shorthand<E, T, M>(encoder: &mut E, value: &T, cache: M) -> Result<(), E::Error>
 where
-    E: TyEncoder,
+    E: TyEncoder<'tcx>,
     M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
-    T: EncodableWithShorthand,
+    T: EncodableWithShorthand<'tcx, E>,
     <T::Variant as DiscriminantKind>::Discriminant: Ord + TryFrom<usize>,
 {
-    let existing_shorthand = cache(encoder).get(value).cloned();
+    let existing_shorthand = cache(encoder).get(value).copied();
     if let Some(shorthand) = existing_shorthand {
         return encoder.emit_usize(shorthand);
     }
@@ -89,13 +121,51 @@ where
     // Check that the shorthand is a not longer than the
     // full encoding itself, i.e., it's an obvious win.
     if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) {
-        cache(encoder).insert(value.clone(), shorthand);
+        cache(encoder).insert(*value, shorthand);
     }
 
     Ok(())
 }
 
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for Ty<'tcx> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        encode_with_shorthand(e, self, TyEncoder::type_shorthands)
+    }
+}
+
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Predicate<'tcx> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        encode_with_shorthand(e, self, TyEncoder::predicate_shorthands)
+    }
+}
+
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        e.encode_alloc_id(self)
+    }
+}
+
+macro_rules! encodable_via_deref {
+    ($($t:ty),+) => {
+        $(impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for $t {
+            fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+                (**self).encode(e)
+            }
+        })*
+    }
+}
+
+encodable_via_deref! {
+    &'tcx ty::TypeckResults<'tcx>,
+    ty::Region<'tcx>,
+    &'tcx mir::Body<'tcx>,
+    &'tcx mir::UnsafetyCheckResult,
+    &'tcx mir::BorrowCheckResult<'tcx>
+}
+
 pub trait TyDecoder<'tcx>: Decoder {
+    const CLEAR_CROSS_CRATE: bool;
+
     fn tcx(&self) -> TyCtxt<'tcx>;
 
     fn peek_byte(&self) -> u8;
@@ -127,10 +197,12 @@ pub trait TyDecoder<'tcx>: Decoder {
     fn positioned_at_shorthand(&self) -> bool {
         (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
     }
+
+    fn decode_alloc_id(&mut self) -> Result<AllocId, Self::Error>;
 }
 
 #[inline]
-pub fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>(
+pub fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
     decoder: &mut D,
 ) -> Result<&'tcx T, D::Error>
 where
@@ -140,172 +212,157 @@ where
 }
 
 #[inline]
-pub fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>(
+pub fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
     decoder: &mut D,
 ) -> Result<&'tcx [T], D::Error>
 where
     D: TyDecoder<'tcx>,
 {
-    Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable>::decode(decoder)?))
+    Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder)?))
 }
 
-#[inline]
-pub fn decode_cnum<D>(decoder: &mut D) -> Result<CrateNum, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let cnum = CrateNum::from_u32(u32::decode(decoder)?);
-    Ok(decoder.map_encoded_cnum_to_current(cnum))
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> {
+    #[allow(rustc::usage_of_ty_tykind)]
+    fn decode(decoder: &mut D) -> Result<Ty<'tcx>, D::Error> {
+        // Handle shorthands first, if we have an usize > 0x80.
+        if decoder.positioned_at_shorthand() {
+            let pos = decoder.read_usize()?;
+            assert!(pos >= SHORTHAND_OFFSET);
+            let shorthand = pos - SHORTHAND_OFFSET;
+
+            decoder.cached_ty_for_shorthand(shorthand, |decoder| {
+                decoder.with_position(shorthand, Ty::decode)
+            })
+        } else {
+            let tcx = decoder.tcx();
+            Ok(tcx.mk_ty(ty::TyKind::decode(decoder)?))
+        }
+    }
 }
 
-#[allow(rustc::usage_of_ty_tykind)]
-#[inline]
-pub fn decode_ty<D>(decoder: &mut D) -> Result<Ty<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    // Handle shorthands first, if we have an usize > 0x80.
-    if decoder.positioned_at_shorthand() {
-        let pos = decoder.read_usize()?;
-        assert!(pos >= SHORTHAND_OFFSET);
-        let shorthand = pos - SHORTHAND_OFFSET;
-
-        decoder.cached_ty_for_shorthand(shorthand, |decoder| {
-            decoder.with_position(shorthand, Ty::decode)
-        })
-    } else {
-        let tcx = decoder.tcx();
-        Ok(tcx.mk_ty(ty::TyKind::decode(decoder)?))
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
+    fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> {
+        // Handle shorthands first, if we have an usize > 0x80.
+        let predicate_kind = if decoder.positioned_at_shorthand() {
+            let pos = decoder.read_usize()?;
+            assert!(pos >= SHORTHAND_OFFSET);
+            let shorthand = pos - SHORTHAND_OFFSET;
+
+            decoder.with_position(shorthand, ty::PredicateKind::decode)
+        } else {
+            ty::PredicateKind::decode(decoder)
+        }?;
+        let predicate = decoder.tcx().mk_predicate(predicate_kind);
+        Ok(predicate)
     }
 }
 
-#[inline]
-pub fn decode_predicate<D>(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    // Handle shorthands first, if we have an usize > 0x80.
-    if decoder.positioned_at_shorthand() {
-        let pos = decoder.read_usize()?;
-        assert!(pos >= SHORTHAND_OFFSET);
-        let shorthand = pos - SHORTHAND_OFFSET;
-
-        decoder.cached_predicate_for_shorthand(shorthand, |decoder| {
-            decoder.with_position(shorthand, ty::Predicate::decode)
-        })
-    } else {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> {
+    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+        let len = decoder.read_usize()?;
         let tcx = decoder.tcx();
-        Ok(tcx.mk_predicate(ty::PredicateKind::decode(decoder)?))
+        Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
     }
 }
 
-#[inline]
-pub fn decode_spanned_predicates<D>(
-    decoder: &mut D,
-) -> Result<&'tcx [(ty::Predicate<'tcx>, Span)], D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let tcx = decoder.tcx();
-    Ok(tcx.arena.alloc_from_iter(
-        (0..decoder.read_usize()?)
-            .map(|_| Decodable::decode(decoder))
-            .collect::<Result<Vec<_>, _>>()?,
-    ))
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for mir::Place<'tcx> {
+    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+        let local: mir::Local = Decodable::decode(decoder)?;
+        let len = decoder.read_usize()?;
+        let projection: &'tcx List<mir::PlaceElem<'tcx>> =
+            decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
+        Ok(mir::Place { local, projection })
+    }
 }
 
-#[inline]
-pub fn decode_substs<D>(decoder: &mut D) -> Result<SubstsRef<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let len = decoder.read_usize()?;
-    let tcx = decoder.tcx();
-    Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> {
+    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+        Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?))
+    }
 }
 
-#[inline]
-pub fn decode_place<D>(decoder: &mut D) -> Result<mir::Place<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let local: mir::Local = Decodable::decode(decoder)?;
-    let len = decoder.read_usize()?;
-    let projection: &'tcx List<mir::PlaceElem<'tcx>> =
-        decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
-    Ok(mir::Place { local, projection })
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> {
+    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+        let len = decoder.read_usize()?;
+        let interned: Result<Vec<CanonicalVarInfo>, _> =
+            (0..len).map(|_| Decodable::decode(decoder)).collect();
+        Ok(decoder.tcx().intern_canonical_var_infos(interned?.as_slice()))
+    }
 }
 
-#[inline]
-pub fn decode_region<D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?))
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AllocId {
+    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+        decoder.decode_alloc_id()
+    }
 }
 
-#[inline]
-pub fn decode_ty_slice<D>(decoder: &mut D) -> Result<&'tcx ty::List<Ty<'tcx>>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let len = decoder.read_usize()?;
-    Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?)
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::SymbolName<'tcx> {
+    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+        Ok(ty::SymbolName::new(decoder.tcx(), &decoder.read_str()?))
+    }
 }
 
-#[inline]
-pub fn decode_adt_def<D>(decoder: &mut D) -> Result<&'tcx ty::AdtDef, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let def_id = DefId::decode(decoder)?;
-    Ok(decoder.tcx().adt_def(def_id))
+macro_rules! impl_decodable_via_ref {
+    ($($t:ty),+) => {
+        $(impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for $t {
+            fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+                RefDecodable::decode(decoder)
+            }
+        })*
+    }
 }
 
-#[inline]
-pub fn decode_symbol_name<D>(decoder: &mut D) -> Result<ty::SymbolName<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    Ok(ty::SymbolName::new(decoder.tcx(), &decoder.read_str()?))
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::AdtDef {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        let def_id = <DefId as Decodable<D>>::decode(decoder)?;
+        Ok(decoder.tcx().adt_def(def_id))
+    }
 }
 
-#[inline]
-pub fn decode_existential_predicate_slice<D>(
-    decoder: &mut D,
-) -> Result<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let len = decoder.read_usize()?;
-    Ok(decoder.tcx().mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        let len = decoder.read_usize()?;
+        Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?)
+    }
 }
 
-#[inline]
-pub fn decode_canonical_var_infos<D>(decoder: &mut D) -> Result<CanonicalVarInfos<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    let len = decoder.read_usize()?;
-    let interned: Result<Vec<CanonicalVarInfo>, _> =
-        (0..len).map(|_| Decodable::decode(decoder)).collect();
-    Ok(decoder.tcx().intern_canonical_var_infos(interned?.as_slice()))
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::ExistentialPredicate<'tcx>> {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        let len = decoder.read_usize()?;
+        Ok(decoder.tcx().mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
+    }
 }
 
-#[inline]
-pub fn decode_const<D>(decoder: &mut D) -> Result<&'tcx ty::Const<'tcx>, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
+    }
 }
 
-#[inline]
-pub fn decode_allocation<D>(decoder: &mut D) -> Result<&'tcx Allocation, D::Error>
-where
-    D: TyDecoder<'tcx>,
-{
-    Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+    }
+}
+
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        Ok(decoder.tcx().arena.alloc_from_iter(
+            (0..decoder.read_usize()?)
+                .map(|_| Decodable::decode(decoder))
+                .collect::<Result<Vec<_>, _>>()?,
+        ))
+    }
+}
+
+impl_decodable_via_ref! {
+    &'tcx ty::TypeckResults<'tcx>,
+    &'tcx ty::List<Ty<'tcx>>,
+    &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+    &'tcx Allocation,
+    &'tcx mir::Body<'tcx>,
+    &'tcx mir::UnsafetyCheckResult,
+    &'tcx mir::BorrowCheckResult<'tcx>
 }
 
 #[macro_export]
@@ -320,42 +377,21 @@ macro_rules! __impl_decoder_methods {
     }
 }
 
-#[macro_export]
 macro_rules! impl_arena_allocatable_decoder {
     ([]$args:tt) => {};
     ([decode $(, $attrs:ident)*]
-     [[$DecoderName:ident [$($typaram:tt),*]], [$name:ident: $ty:ty, $gen_ty:ty], $tcx:lifetime]) => {
-         // FIXME(#36588): These impls are horribly unsound as they allow
-         // the caller to pick any lifetime for `'tcx`, including `'static`.
-        #[allow(unused_lifetimes)]
-        impl<'_x, '_y, '_z, '_w, '_a, $($typaram),*> SpecializedDecoder<&'_a $gen_ty>
-        for $DecoderName<$($typaram),*>
-        where &'_a $gen_ty: UseSpecializedDecodable
-        {
+     [[$name:ident: $ty:ty], $tcx:lifetime]) => {
+        impl<$tcx, D: TyDecoder<$tcx>> RefDecodable<$tcx, D> for $ty {
             #[inline]
-            fn specialized_decode(&mut self) -> Result<&'_a $gen_ty, Self::Error> {
-                unsafe {
-                    std::mem::transmute::<
-                        Result<&$tcx $ty, Self::Error>,
-                        Result<&'_a $gen_ty, Self::Error>,
-                    >(decode_arena_allocable(self))
-                }
+            fn decode(decoder: &mut D) -> Result<&$tcx Self, D::Error> {
+                decode_arena_allocable(decoder)
             }
         }
 
-        #[allow(unused_lifetimes)]
-        impl<'_x, '_y, '_z, '_w, '_a, $($typaram),*> SpecializedDecoder<&'_a [$gen_ty]>
-        for $DecoderName<$($typaram),*>
-        where &'_a [$gen_ty]: UseSpecializedDecodable
-        {
+        impl<$tcx, D: TyDecoder<$tcx>> RefDecodable<$tcx, D> for [$ty] {
             #[inline]
-            fn specialized_decode(&mut self) -> Result<&'_a [$gen_ty], Self::Error> {
-                unsafe {
-                    std::mem::transmute::<
-                        Result<&$tcx [$ty], Self::Error>,
-                        Result<&'_a [$gen_ty], Self::Error>,
-                    >(decode_arena_allocable_slice(self))
-                }
+            fn decode(decoder: &mut D) -> Result<&$tcx Self, D::Error> {
+                decode_arena_allocable_slice(decoder)
             }
         }
     };
@@ -364,38 +400,30 @@ macro_rules! impl_arena_allocatable_decoder {
     };
 }
 
-#[macro_export]
 macro_rules! impl_arena_allocatable_decoders {
-    ($args:tt, [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => {
+    ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
         $(
-            impl_arena_allocatable_decoder!($a [$args, [$name: $ty, $gen_ty], $tcx]);
+            impl_arena_allocatable_decoder!($a [[$name: $ty], $tcx]);
         )*
     }
 }
 
+rustc_hir::arena_types!(impl_arena_allocatable_decoders, [], 'tcx);
+arena_types!(impl_arena_allocatable_decoders, [], 'tcx);
+
 #[macro_export]
 macro_rules! implement_ty_decoder {
     ($DecoderName:ident <$($typaram:tt),*>) => {
         mod __ty_decoder_impl {
             use std::borrow::Cow;
-            use std::mem::transmute;
-
-            use rustc_serialize::{Decoder, SpecializedDecoder, UseSpecializedDecodable};
-
-            use $crate::infer::canonical::CanonicalVarInfos;
-            use $crate::ty;
-            use $crate::ty::codec::*;
-            use $crate::ty::subst::InternalSubsts;
-            use rustc_hir::def_id::CrateNum;
-
-            use rustc_span::Span;
+            use rustc_serialize::Decoder;
 
             use super::$DecoderName;
 
             impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> {
                 type Error = String;
 
-                __impl_decoder_methods! {
+                $crate::__impl_decoder_methods! {
                     read_nil -> ();
 
                     read_u128 -> u128;
@@ -423,135 +451,6 @@ macro_rules! implement_ty_decoder {
                     self.opaque.error(err)
                 }
             }
-
-            // FIXME(#36588): These impls are horribly unsound as they allow
-            // the caller to pick any lifetime for `'tcx`, including `'static`.
-
-            arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx);
-
-            impl<$($typaram),*> SpecializedDecoder<CrateNum>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> {
-                    decode_cnum(self)
-                }
-            }
-
-            impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x ty::TyS<'_y>>
-            for $DecoderName<$($typaram),*>
-            where &'_x ty::TyS<'_y>: UseSpecializedDecodable
-            {
-                fn specialized_decode(&mut self) -> Result<&'_x ty::TyS<'_y>, Self::Error> {
-                    unsafe {
-                        transmute::<
-                            Result<ty::Ty<'tcx>, Self::Error>,
-                            Result<&'_x ty::TyS<'_y>, Self::Error>,
-                        >(decode_ty(self))
-                    }
-                }
-            }
-
-            impl<'_x, $($typaram),*> SpecializedDecoder<ty::Predicate<'_x>>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(&mut self) -> Result<ty::Predicate<'_x>, Self::Error> {
-                    unsafe {
-                        transmute::<
-                            Result<ty::Predicate<'tcx>, Self::Error>,
-                            Result<ty::Predicate<'_x>, Self::Error>,
-                        >(decode_predicate(self))
-                    }
-                }
-            }
-
-            impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x [(ty::Predicate<'_y>, Span)]>
-            for $DecoderName<$($typaram),*>
-            where &'_x [(ty::Predicate<'_y>, Span)]: UseSpecializedDecodable {
-                fn specialized_decode(&mut self)
-                                      -> Result<&'_x [(ty::Predicate<'_y>, Span)], Self::Error>
-                {
-                    unsafe { transmute(decode_spanned_predicates(self)) }
-                }
-            }
-
-            impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x InternalSubsts<'_y>>
-            for $DecoderName<$($typaram),*>
-            where &'_x InternalSubsts<'_y>: UseSpecializedDecodable {
-                fn specialized_decode(&mut self) -> Result<&'_x InternalSubsts<'_y>, Self::Error> {
-                    unsafe { transmute(decode_substs(self)) }
-                }
-            }
-
-            impl<'_x, $($typaram),*> SpecializedDecoder<$crate::mir::Place<'_x>>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(
-                    &mut self
-                ) -> Result<$crate::mir::Place<'_x>, Self::Error> {
-                    unsafe { transmute(decode_place(self)) }
-                }
-            }
-
-            impl<'_x, $($typaram),*> SpecializedDecoder<ty::Region<'_x>>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(&mut self) -> Result<ty::Region<'_x>, Self::Error> {
-                    unsafe { transmute(decode_region(self)) }
-                }
-            }
-
-            impl<'_x, '_y, '_z, $($typaram),*> SpecializedDecoder<&'_x ty::List<&'_y ty::TyS<'_z>>>
-            for $DecoderName<$($typaram),*>
-            where &'_x ty::List<&'_y ty::TyS<'_z>>: UseSpecializedDecodable {
-                fn specialized_decode(&mut self)
-                                      -> Result<&'_x ty::List<&'_y ty::TyS<'_z>>, Self::Error> {
-                    unsafe { transmute(decode_ty_slice(self)) }
-                }
-            }
-
-            impl<'_x, $($typaram),*> SpecializedDecoder<&'_x ty::AdtDef>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(&mut self) -> Result<&'_x ty::AdtDef, Self::Error> {
-                    unsafe { transmute(decode_adt_def(self)) }
-                }
-            }
-
-            impl<'_x, $($typaram),*> SpecializedDecoder<ty::SymbolName<'_x>>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(&mut self) -> Result<ty::SymbolName<'_x>, Self::Error> {
-                    unsafe { transmute(decode_symbol_name(self)) }
-                }
-            }
-
-            impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x ty::List<ty::ExistentialPredicate<'_y>>>
-            for $DecoderName<$($typaram),*>
-            where &'_x ty::List<ty::ExistentialPredicate<'_y>>: UseSpecializedDecodable {
-                fn specialized_decode(&mut self)
-                    -> Result<&'_x ty::List<ty::ExistentialPredicate<'_y>>, Self::Error> {
-                        unsafe { transmute(decode_existential_predicate_slice(self)) }
-                }
-            }
-
-            impl<'_x, $($typaram),*> SpecializedDecoder<CanonicalVarInfos<'_x>>
-                for $DecoderName<$($typaram),*> {
-                fn specialized_decode(&mut self)
-                    -> Result<CanonicalVarInfos<'_x>, Self::Error> {
-                        unsafe { transmute(decode_canonical_var_infos(self)) }
-                }
-            }
-
-            impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x $crate::ty::Const<'_y>>
-            for $DecoderName<$($typaram),*>
-            where &'_x $crate::ty::Const<'_y>: UseSpecializedDecodable {
-                fn specialized_decode(&mut self) -> Result<&'_x ty::Const<'_y>, Self::Error> {
-                    unsafe { transmute(decode_const(self)) }
-                }
-            }
-
-            impl<'_x, $($typaram),*> SpecializedDecoder<&'_x $crate::mir::interpret::Allocation>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(
-                    &mut self
-                ) -> Result<&'_x $crate::mir::interpret::Allocation, Self::Error> {
-                    unsafe { transmute(decode_allocation(self)) }
-                }
-            }
         }
-    };
+    }
 }
diff --git a/src/librustc_middle/ty/consts.rs b/src/librustc_middle/ty/consts.rs
index c0b5693dc59..e883c7c6dcd 100644
--- a/src/librustc_middle/ty/consts.rs
+++ b/src/librustc_middle/ty/consts.rs
@@ -15,7 +15,7 @@ pub use int::*;
 pub use kind::*;
 
 /// Typed constant value.
-#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
 #[derive(HashStable)]
 pub struct Const<'tcx> {
     pub ty: Ty<'tcx>,
diff --git a/src/librustc_middle/ty/consts/kind.rs b/src/librustc_middle/ty/consts/kind.rs
index e8a1e714a8f..a4c177160f5 100644
--- a/src/librustc_middle/ty/consts/kind.rs
+++ b/src/librustc_middle/ty/consts/kind.rs
@@ -10,7 +10,7 @@ use rustc_macros::HashStable;
 use rustc_target::abi::Size;
 
 /// Represents a constant in Rust.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
 pub enum ConstKind<'tcx> {
     /// A const generic parameter.
@@ -68,7 +68,7 @@ impl<'tcx> ConstKind<'tcx> {
 }
 
 /// An inference variable for a const, for use in const generics.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
 pub enum InferConst<'tcx> {
     /// Infer the value of the const.
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index d6bcfbf49cf..ba1f78e337a 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -263,7 +263,7 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
 }
 
 /// All information necessary to validate and reveal an `impl Trait`.
-#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct ResolvedOpaqueTy<'tcx> {
     /// The revealed type as seen by this function.
     pub concrete_type: Ty<'tcx>,
@@ -291,7 +291,7 @@ pub struct ResolvedOpaqueTy<'tcx> {
 ///
 /// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
 /// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
-#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
 pub struct GeneratorInteriorTypeCause<'tcx> {
     /// Type of the captured binding.
     pub ty: Ty<'tcx>,
@@ -305,7 +305,7 @@ pub struct GeneratorInteriorTypeCause<'tcx> {
     pub expr: Option<hir::HirId>,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(TyEncodable, TyDecodable, Debug)]
 pub struct TypeckResults<'tcx> {
     /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
     pub hir_owner: LocalDefId,
@@ -728,7 +728,7 @@ rustc_index::newtype_index! {
 pub type CanonicalUserTypeAnnotations<'tcx> =
     IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct CanonicalUserTypeAnnotation<'tcx> {
     pub user_ty: CanonicalUserType<'tcx>,
     pub span: Span,
@@ -787,7 +787,7 @@ impl CanonicalUserType<'tcx> {
 /// A user-given type annotation attached to a constant. These arise
 /// from constants that are named via paths, like `Foo::<A>::new` and
 /// so forth.
-#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub enum UserType<'tcx> {
     Ty(Ty<'tcx>),
@@ -1333,7 +1333,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn serialize_query_result_cache<E>(self, encoder: &mut E) -> Result<(), E::Error>
     where
-        E: ty::codec::TyEncoder,
+        E: ty::codec::OpaqueEncoder,
     {
         self.queries.on_disk_cache.serialize(self, encoder)
     }
diff --git a/src/librustc_middle/ty/fast_reject.rs b/src/librustc_middle/ty/fast_reject.rs
index b0fb179b18b..7456020ee9b 100644
--- a/src/librustc_middle/ty/fast_reject.rs
+++ b/src/librustc_middle/ty/fast_reject.rs
@@ -17,7 +17,7 @@ pub type SimplifiedType = SimplifiedTypeGen<DefId>;
 /// because we sometimes need to use SimplifiedTypeGen values as stable sorting
 /// keys (in which case we use a DefPathHash as id-type) but in the general case
 /// the non-stable but fast to construct DefId-version is the better choice.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
 pub enum SimplifiedTypeGen<D>
 where
     D: Copy + Debug + Ord + Eq,
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..e6dafd4965b 100644
--- a/src/librustc_middle/ty/instance.rs
+++ b/src/librustc_middle/ty/instance.rs
@@ -15,14 +15,14 @@ use std::fmt;
 /// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
 /// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval
 /// will do all required substitution as they run.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, Lift)]
 pub struct Instance<'tcx> {
     pub def: InstanceDef<'tcx>,
     pub substs: SubstsRef<'tcx>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum InstanceDef<'tcx> {
     /// A user-defined callable item.
     ///
@@ -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..16e65d2cca4 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -165,7 +165,7 @@ pub const FAT_PTR_ADDR: usize = 0;
 /// - For a slice, this is the length.
 pub const FAT_PTR_EXTRA: usize = 1;
 
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     SizeOverflow(Ty<'tcx>),
@@ -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/list.rs b/src/librustc_middle/ty/list.rs
index 92d6dbb5f90..fe390adf89f 100644
--- a/src/librustc_middle/ty/list.rs
+++ b/src/librustc_middle/ty/list.rs
@@ -76,9 +76,16 @@ impl<T: fmt::Debug> fmt::Debug for List<T> {
     }
 }
 
-impl<T: Encodable> Encodable for List<T> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> {
     #[inline]
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        (**self).encode(s)
+    }
+}
+
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for &List<T> {
+    #[inline]
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         (**self).encode(s)
     }
 }
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 0102225b9b5..81e60a7fd37 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -89,12 +89,11 @@ pub use self::query::queries;
 
 pub use self::consts::{Const, ConstInt, ConstKind, InferConst};
 
+pub mod _match;
 pub mod adjustment;
 pub mod binding;
 pub mod cast;
-#[macro_use]
 pub mod codec;
-pub mod _match;
 mod erase_regions;
 pub mod error;
 pub mod fast_reject;
@@ -171,7 +170,7 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub enum ImplPolarity {
     /// `impl Trait for Type`
     Positive,
@@ -316,7 +315,7 @@ impl<'tcx> AssociatedItems<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
 pub enum Visibility {
     /// Visible everywhere (including in other crates).
     Public,
@@ -403,7 +402,7 @@ impl Visibility {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, RustcDecodable, RustcEncodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyDecodable, TyEncodable, HashStable)]
 pub enum Variance {
     Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
     Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
@@ -575,10 +574,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;
     }
 }
 
@@ -656,13 +651,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
 #[rustc_diagnostic_item = "Ty"]
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
-impl<'tcx> rustc_serialize::UseSpecializedEncodable for Ty<'tcx> {}
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for Ty<'tcx> {}
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx List<Ty<'tcx>> {}
-
 pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>;
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub struct UpvarPath {
     pub hir_id: hir::HirId,
 }
@@ -670,13 +661,13 @@ pub struct UpvarPath {
 /// Upvars do not get their own `NodeId`. Instead, we use the pair of
 /// the original var ID (that is, the root variable that is referenced
 /// by the upvar) and the ID of the closure expression.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub struct UpvarId {
     pub var_path: UpvarPath,
     pub closure_expr_id: LocalDefId,
 }
 
-#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, HashStable)]
+#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     ImmBorrow,
@@ -724,7 +715,7 @@ pub enum BorrowKind {
 
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
-#[derive(PartialEq, Clone, Debug, Copy, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
 pub enum UpvarCapture<'tcx> {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
@@ -735,7 +726,7 @@ pub enum UpvarCapture<'tcx> {
     ByRef(UpvarBorrow<'tcx>),
 }
 
-#[derive(PartialEq, Clone, Copy, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, HashStable)]
 pub struct UpvarBorrow<'tcx> {
     /// The kind of borrow: by-ref upvars have access to shared
     /// immutable borrows, which are not part of the normal language
@@ -770,7 +761,7 @@ impl ty::EarlyBoundRegion {
     }
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum GenericParamDefKind {
     Lifetime,
     Type {
@@ -791,7 +782,7 @@ impl GenericParamDefKind {
     }
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct GenericParamDef {
     pub name: Symbol,
     pub def_id: DefId,
@@ -835,7 +826,7 @@ pub struct GenericParamCount {
 ///
 /// The ordering of parameters is the same as in `Subst` (excluding child generics):
 /// `Self` (optionally), `Lifetime` params..., `Type` params...
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct Generics {
     pub parent: Option<DefId>,
     pub parent_count: usize,
@@ -937,7 +928,7 @@ impl<'tcx> Generics {
 }
 
 /// Bounds on generics.
-#[derive(Copy, Clone, Default, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct GenericPredicates<'tcx> {
     pub parent: Option<DefId>,
     pub predicates: &'tcx [(Predicate<'tcx>, Span)],
@@ -1029,9 +1020,6 @@ pub struct Predicate<'tcx> {
     inner: &'tcx PredicateInner<'tcx>,
 }
 
-impl rustc_serialize::UseSpecializedEncodable for Predicate<'_> {}
-impl rustc_serialize::UseSpecializedDecodable for Predicate<'_> {}
-
 impl<'tcx> PartialEq for Predicate<'tcx> {
     fn eq(&self, other: &Self) -> bool {
         // `self.kind` is always interned.
@@ -1107,7 +1095,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub enum PredicateKind<'tcx> {
     /// `for<'a>: ...`
@@ -1115,7 +1103,7 @@ pub enum PredicateKind<'tcx> {
     Atom(PredicateAtom<'tcx>),
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub enum PredicateAtom<'tcx> {
     /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
@@ -1265,7 +1253,7 @@ impl<'tcx> Predicate<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>,
@@ -1290,7 +1278,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
 pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>;
@@ -1299,7 +1287,7 @@ pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'t
 pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>;
 pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<TypeOutlivesPredicate<'tcx>>;
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct SubtypePredicate<'tcx> {
     pub a_is_expected: bool,
@@ -1320,7 +1308,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<SubtypePredicate<'tcx>>;
 /// equality between arbitrary types. Processing an instance of
 /// Form #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
@@ -1589,7 +1577,7 @@ impl UniverseIndex {
 /// basically a name -- distinct bound regions within the same
 /// universe are just two regions with an unknown relationship to one
 /// another.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)]
 pub struct Placeholder<T> {
     pub universe: UniverseIndex,
     pub name: T,
@@ -1639,7 +1627,7 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
 ///     a.foo::<7>();
 /// }
 /// ```
-#[derive(Copy, Clone, Debug, TypeFoldable, Lift, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, Lift, TyEncodable, TyDecodable)]
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 #[derive(Hash, HashStable)]
 pub struct WithOptConstParam<T> {
@@ -2110,7 +2098,7 @@ impl<'tcx> VariantDef {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum VariantDiscr {
     /// Explicit value for this variant, i.e., `X = 123`.
     /// The `DefId` corresponds to the embedded constant.
@@ -2182,14 +2170,12 @@ impl Hash for AdtDef {
     }
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedEncodable for &'tcx AdtDef {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for AdtDef {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         self.did.encode(s)
     }
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx AdtDef {}
-
 impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         thread_local! {
@@ -2233,7 +2219,7 @@ impl Into<DataTypeKind> for AdtKind {
 }
 
 bitflags! {
-    #[derive(RustcEncodable, RustcDecodable, Default, HashStable)]
+    #[derive(TyEncodable, TyDecodable, Default, HashStable)]
     pub struct ReprFlags: u8 {
         const IS_C               = 1 << 0;
         const IS_SIMD            = 1 << 1;
@@ -2250,7 +2236,7 @@ bitflags! {
 }
 
 /// Represents the repr options provided by the user,
-#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default, HashStable)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Default, HashStable)]
 pub struct ReprOptions {
     pub int: Option<attr::IntType>,
     pub align: Option<Align>,
@@ -2694,7 +2680,7 @@ impl<'tcx> FieldDef {
 ///
 /// You can get the environment type of a closure using
 /// `tcx.closure_env_ty()`.
-#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum ClosureKind {
     // Warning: Ordering is significant here! The ordering is chosen
@@ -3145,7 +3131,7 @@ pub struct CrateInherentImpls {
     pub inherent_impls: DefIdMap<Vec<DefId>>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
 pub struct SymbolName<'tcx> {
     /// `&str` gives a consistent ordering, which ensures reproducible builds.
     pub name: &'tcx str,
@@ -3170,12 +3156,3 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
         fmt::Display::fmt(&self.name, fmt)
     }
 }
-
-impl<'tcx> rustc_serialize::UseSpecializedEncodable for SymbolName<'tcx> {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(self.name)
-    }
-}
-
-// The decoding takes place in `decode_symbol_name()`.
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for SymbolName<'tcx> {}
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_middle/ty/query/on_disk_cache.rs b/src/librustc_middle/ty/query/on_disk_cache.rs
index 08b0bfecf49..007b46b1176 100644
--- a/src/librustc_middle/ty/query/on_disk_cache.rs
+++ b/src/librustc_middle/ty/query/on_disk_cache.rs
@@ -1,28 +1,24 @@
 use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
-use crate::mir::interpret;
 use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
-use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
+use crate::mir::{self, interpret};
+use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder};
 use crate::ty::context::TyCtxt;
 use crate::ty::{self, Ty};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder, FingerprintEncoder};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathHash;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_serialize::{
-    opaque, Decodable, Decoder, Encodable, Encoder, SpecializedDecoder, SpecializedEncoder,
-    UseSpecializedDecodable, UseSpecializedEncodable,
-};
+use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
 use rustc_session::{CrateDisambiguator, Session};
 use rustc_span::hygiene::{
     ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
     SyntaxContext, SyntaxContextData,
 };
 use rustc_span::source_map::{SourceMap, StableSourceFileId};
-use rustc_span::symbol::Ident;
 use rustc_span::CachingSourceMapView;
 use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP};
 use std::mem;
@@ -87,7 +83,7 @@ pub struct OnDiskCache<'sess> {
 }
 
 // This type is used only for serialization and deserialization.
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 struct Footer {
     file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
     prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
@@ -105,10 +101,10 @@ type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
 type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
 type EncodedDiagnostics = Vec<Diagnostic>;
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
 struct SourceFileIndex(u32);
 
-#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)]
 struct AbsoluteBytePos(u32);
 
 impl AbsoluteBytePos {
@@ -182,7 +178,7 @@ impl<'sess> OnDiskCache<'sess> {
 
     pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(), E::Error>
     where
-        E: TyEncoder,
+        E: OpaqueEncoder,
     {
         // Serializing the `DepGraph` should not modify it.
         tcx.dep_graph.with_ignore(|| {
@@ -333,7 +329,7 @@ impl<'sess> OnDiskCache<'sess> {
 
             // Encode the position of the footer as the last 8 bytes of the
             // file so we know where to look for it.
-            IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
+            IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder.opaque())?;
 
             // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
             // of the footer must be the last thing in the data stream.
@@ -380,13 +376,13 @@ impl<'sess> OnDiskCache<'sess> {
 
     /// Returns the cached query result if there is something in the cache for
     /// the given `SerializedDepNodeIndex`; otherwise returns `None`.
-    pub fn try_load_query_result<T>(
+    crate fn try_load_query_result<'tcx, T>(
         &self,
-        tcx: TyCtxt<'_>,
+        tcx: TyCtxt<'tcx>,
         dep_node_index: SerializedDepNodeIndex,
     ) -> Option<T>
     where
-        T: Decodable,
+        T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
     {
         self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
     }
@@ -417,7 +413,7 @@ impl<'sess> OnDiskCache<'sess> {
         debug_tag: &'static str,
     ) -> Option<T>
     where
-        T: Decodable,
+        T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
     {
         let pos = index.get(&dep_node_index).cloned()?;
 
@@ -427,14 +423,14 @@ impl<'sess> OnDiskCache<'sess> {
         })
     }
 
-    fn with_decoder<'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
+    fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
         &'sess self,
         tcx: TyCtxt<'tcx>,
         pos: AbsoluteBytePos,
         f: F,
     ) -> T
     where
-        T: Decodable,
+        T: Decodable<CacheDecoder<'a, 'tcx>>,
     {
         let cnum_map =
             self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
@@ -492,7 +488,7 @@ impl<'sess> OnDiskCache<'sess> {
 /// A decoder that can read from the incr. comp. cache. It is similar to the one
 /// we use for crate metadata decoding in that it can rebase spans and eventually
 /// will also handle things that contain `Ty` instances.
-struct CacheDecoder<'a, 'tcx> {
+crate struct CacheDecoder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     opaque: opaque::Decoder<'a>,
     source_map: &'a SourceMap,
@@ -547,8 +543,8 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
 // tag matches and the correct amount of bytes was read.
 fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error>
 where
-    T: Decodable + Eq + ::std::fmt::Debug,
-    V: Decodable,
+    T: Decodable<D> + Eq + ::std::fmt::Debug,
+    V: Decodable<D>,
     D: DecoderWithPosition,
 {
     let start_pos = decoder.position();
@@ -565,6 +561,8 @@ where
 }
 
 impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
+    const CLEAR_CROSS_CRATE: bool = false;
+
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
@@ -642,14 +640,19 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
     fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
         self.cnum_map[cnum].unwrap_or_else(|| bug!("could not find new `CrateNum` for {:?}", cnum))
     }
+
+    fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> {
+        let alloc_decoding_session = self.alloc_decoding_session;
+        alloc_decoding_session.decode_alloc_id(self)
+    }
 }
 
-implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
+crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
 
-impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<SyntaxContext, Self::Error> {
-        let syntax_contexts = self.syntax_contexts;
-        rustc_span::hygiene::decode_syntax_context(self, self.hygiene_context, |this, id| {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext {
+    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        let syntax_contexts = decoder.syntax_contexts;
+        rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| {
             // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing.
             // We look up the position of the associated `SyntaxData` and decode it.
             let pos = syntax_contexts.get(&id).unwrap();
@@ -661,12 +664,12 @@ impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for CacheDecoder<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<ExpnId> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<ExpnId, Self::Error> {
-        let expn_data = self.expn_data;
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
+    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        let expn_data = decoder.expn_data;
         rustc_span::hygiene::decode_expn_id(
-            self,
-            ExpnDataDecodeMode::incr_comp(self.hygiene_context),
+            decoder,
+            ExpnDataDecodeMode::incr_comp(decoder.hygiene_context),
             |this, index| {
                 // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing.
                 // We look up the position of the associated `ExpnData` and decode it.
@@ -683,16 +686,9 @@ impl<'a, 'tcx> SpecializedDecoder<ExpnId> for CacheDecoder<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
-        let alloc_decoding_session = self.alloc_decoding_session;
-        alloc_decoding_session.decode_alloc_id(self)
-    }
-}
-
-impl<'a, 'tcx> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
-        let tag: u8 = Decodable::decode(self)?;
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
+    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        let tag: u8 = Decodable::decode(decoder)?;
 
         if tag == TAG_INVALID_SPAN {
             return Ok(DUMMY_SP);
@@ -700,13 +696,13 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx> {
             debug_assert_eq!(tag, TAG_VALID_SPAN);
         }
 
-        let file_lo_index = SourceFileIndex::decode(self)?;
-        let line_lo = usize::decode(self)?;
-        let col_lo = BytePos::decode(self)?;
-        let len = BytePos::decode(self)?;
-        let ctxt = SyntaxContext::decode(self)?;
+        let file_lo_index = SourceFileIndex::decode(decoder)?;
+        let line_lo = usize::decode(decoder)?;
+        let col_lo = BytePos::decode(decoder)?;
+        let len = BytePos::decode(decoder)?;
+        let ctxt = SyntaxContext::decode(decoder)?;
 
-        let file_lo = self.file_index_to_file(file_lo_index);
+        let file_lo = decoder.file_index_to_file(file_lo_index);
         let lo = file_lo.lines[line_lo - 1] + col_lo;
         let hi = lo + len;
 
@@ -714,10 +710,10 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<Ident> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<Ident, Self::Error> {
-        // FIXME: Handle hygiene in incremental
-        bug!("Trying to decode Ident for incremental");
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        let cnum = CrateNum::from_u32(u32::decode(d)?);
+        Ok(d.map_encoded_cnum_to_current(cnum))
     }
 }
 
@@ -725,43 +721,69 @@ impl<'a, 'tcx> SpecializedDecoder<Ident> for CacheDecoder<'a, 'tcx> {
 // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic
 // because we would not know how to transform the `DefIndex` to the current
 // context.
-impl<'a, 'tcx> SpecializedDecoder<DefIndex> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
-        bug!("trying to decode `DefIndex` outside the context of a `DefId`")
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<DefIndex, String> {
+        Err(d.error("trying to decode `DefIndex` outside the context of a `DefId`"))
     }
 }
 
 // Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two
 // compilation sessions. We use the `DefPathHash`, which is stable across
 // sessions, to map the old `DefId` to the new one.
-impl<'a, 'tcx> SpecializedDecoder<DefId> for CacheDecoder<'a, 'tcx> {
-    #[inline]
-    fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         // Load the `DefPathHash` which is was we encoded the `DefId` as.
-        let def_path_hash = DefPathHash::decode(self)?;
+        let def_path_hash = DefPathHash::decode(d)?;
 
         // Using the `DefPathHash`, we can lookup the new `DefId`.
-        Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash])
+        Ok(d.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash])
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<LocalDefId> for CacheDecoder<'a, 'tcx> {
-    #[inline]
-    fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
-        Ok(DefId::decode(self)?.expect_local())
+impl<'a, 'tcx> FingerprintDecoder for CacheDecoder<'a, 'tcx> {
+    fn decode_fingerprint(&mut self) -> Result<Fingerprint, Self::Error> {
+        Fingerprint::decode_opaque(&mut self.opaque)
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<Fingerprint> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<Fingerprint, Self::Error> {
-        Fingerprint::decode_opaque(&mut self.opaque)
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        RefDecodable::decode(d)
+    }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
+    for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
+{
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        RefDecodable::decode(d)
+    }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        RefDecodable::decode(d)
+    }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
+    for &'tcx [rustc_ast::ast::InlineAsmTemplatePiece]
+{
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        RefDecodable::decode(d)
+    }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        RefDecodable::decode(d)
     }
 }
 
 //- ENCODING -------------------------------------------------------------------
 
 /// An encoder that can write the incr. comp. cache.
-struct CacheEncoder<'a, 'tcx, E: ty_codec::TyEncoder> {
+struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
     tcx: TyCtxt<'tcx>,
     encoder: &'a mut E,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
@@ -774,7 +796,7 @@ struct CacheEncoder<'a, 'tcx, E: ty_codec::TyEncoder> {
 
 impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
 where
-    E: 'a + TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
     fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
         self.file_to_file_index[&(&*source_file as *const SourceFile)]
@@ -785,7 +807,7 @@ where
     /// encode the specified tag, then the given value, then the number of
     /// bytes taken up by tag and value. On decoding, we can then verify that
     /// we get the expected tag and read the expected number of bytes.
-    fn encode_tagged<T: Encodable, V: Encodable>(
+    fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(
         &mut self,
         tag: T,
         value: &V,
@@ -800,170 +822,111 @@ where
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<interpret::AllocId> for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + TyEncoder,
-{
-    fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
-        let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
-        index.encode(self)
+impl<'a, 'tcx> FingerprintEncoder for CacheEncoder<'a, 'tcx, rustc_serialize::opaque::Encoder> {
+    fn encode_fingerprint(&mut self, f: &Fingerprint) -> opaque::EncodeResult {
+        f.encode_opaque(self.encoder)
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<SyntaxContext> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for SyntaxContext
 where
-    E: 'a + TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
-    fn specialized_encode(&mut self, ctxt: &SyntaxContext) -> Result<(), Self::Error> {
-        rustc_span::hygiene::raw_encode_syntax_context(*ctxt, self.hygiene_context, self)
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+        rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s)
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<ExpnId> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for ExpnId
 where
-    E: 'a + TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
-    fn specialized_encode(&mut self, expn: &ExpnId) -> Result<(), Self::Error> {
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
         rustc_span::hygiene::raw_encode_expn_id(
-            *expn,
-            self.hygiene_context,
+            *self,
+            s.hygiene_context,
             ExpnDataEncodeMode::IncrComp,
-            self,
+            s,
         )
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for Span
 where
-    E: 'a + TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
-    fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
-        if *span == DUMMY_SP {
-            return TAG_INVALID_SPAN.encode(self);
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+        if *self == DUMMY_SP {
+            return TAG_INVALID_SPAN.encode(s);
         }
 
-        let span_data = span.data();
-        let (file_lo, line_lo, col_lo) =
-            match self.source_map.byte_pos_to_line_and_col(span_data.lo) {
-                Some(pos) => pos,
-                None => return TAG_INVALID_SPAN.encode(self),
-            };
+        let span_data = self.data();
+        let (file_lo, line_lo, col_lo) = match s.source_map.byte_pos_to_line_and_col(span_data.lo) {
+            Some(pos) => pos,
+            None => return TAG_INVALID_SPAN.encode(s),
+        };
 
         if !file_lo.contains(span_data.hi) {
-            return TAG_INVALID_SPAN.encode(self);
+            return TAG_INVALID_SPAN.encode(s);
         }
 
         let len = span_data.hi - span_data.lo;
 
-        let source_file_index = self.source_file_index(file_lo);
+        let source_file_index = s.source_file_index(file_lo);
 
-        TAG_VALID_SPAN.encode(self)?;
-        source_file_index.encode(self)?;
-        line_lo.encode(self)?;
-        col_lo.encode(self)?;
-        len.encode(self)?;
-        span_data.ctxt.encode(self)?;
-        Ok(())
+        TAG_VALID_SPAN.encode(s)?;
+        source_file_index.encode(s)?;
+        line_lo.encode(s)?;
+        col_lo.encode(s)?;
+        len.encode(s)?;
+        span_data.ctxt.encode(s)
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<Ident> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E>
 where
-    E: 'a + ty_codec::TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
-    fn specialized_encode(&mut self, _: &Ident) -> Result<(), Self::Error> {
-        // We don't currently encode enough information to ensure hygiene works
-        // with incremental, so panic rather than risk incremental bugs.
+    const CLEAR_CROSS_CRATE: bool = false;
 
-        // FIXME: handle hygiene in incremental.
-        bug!("trying to encode `Ident` for incremental");
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
     }
-}
-
-impl<'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + TyEncoder,
-{
-    #[inline]
     fn position(&self) -> usize {
-        self.encoder.position()
+        self.encoder.encoder_position()
     }
-}
-
-impl<'a, 'tcx, E> SpecializedEncoder<CrateNum> for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + TyEncoder,
-{
-    #[inline]
-    fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> {
-        self.emit_u32(cnum.as_u32())
+    fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
+        &mut self.type_shorthands
     }
-}
-
-impl<'a, 'b, 'c, 'tcx, E> SpecializedEncoder<&'b ty::TyS<'c>> for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + TyEncoder,
-    &'b ty::TyS<'c>: UseSpecializedEncodable,
-{
-    #[inline]
-    fn specialized_encode(&mut self, ty: &&'b ty::TyS<'c>) -> Result<(), Self::Error> {
-        debug_assert!(self.tcx.lift(ty).is_some());
-        let ty = unsafe { std::mem::transmute::<&&'b ty::TyS<'c>, &&'tcx ty::TyS<'tcx>>(ty) };
-        ty_codec::encode_with_shorthand(self, ty, |encoder| &mut encoder.type_shorthands)
-    }
-}
-
-impl<'a, 'b, 'tcx, E> SpecializedEncoder<ty::Predicate<'b>> for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + TyEncoder,
-{
-    #[inline]
-    fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> {
-        debug_assert!(self.tcx.lift(predicate).is_some());
-        let predicate =
-            unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) };
-        ty_codec::encode_with_shorthand(self, predicate, |encoder| {
-            &mut encoder.predicate_shorthands
-        })
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::Predicate<'tcx>, usize> {
+        &mut self.predicate_shorthands
     }
-}
+    fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
+        let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
 
-impl<'a, 'tcx, E> SpecializedEncoder<DefId> for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + TyEncoder,
-{
-    #[inline]
-    fn specialized_encode(&mut self, id: &DefId) -> Result<(), Self::Error> {
-        let def_path_hash = self.tcx.def_path_hash(*id);
-        def_path_hash.encode(self)
+        index.encode(self)
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<LocalDefId> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId
 where
-    E: 'a + TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
-    #[inline]
-    fn specialized_encode(&mut self, id: &LocalDefId) -> Result<(), Self::Error> {
-        id.to_def_id().encode(self)
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+        let def_path_hash = s.tcx.def_path_hash(*self);
+        def_path_hash.encode(s)
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<DefIndex> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefIndex
 where
-    E: 'a + TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
-    fn specialized_encode(&mut self, _: &DefIndex) -> Result<(), Self::Error> {
+    fn encode(&self, _: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
         bug!("encoding `DefIndex` without context");
     }
 }
 
-impl<'a, 'tcx> SpecializedEncoder<Fingerprint> for CacheEncoder<'a, 'tcx, opaque::Encoder> {
-    fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
-        f.encode_opaque(&mut self.encoder)
-    }
-}
-
 macro_rules! encoder_methods {
     ($($name:ident($ty:ty);)*) => {
         #[inline]
@@ -975,7 +938,7 @@ macro_rules! encoder_methods {
 
 impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E>
 where
-    E: 'a + TyEncoder,
+    E: 'a + OpaqueEncoder,
 {
     type Error = E::Error;
 
@@ -1014,32 +977,29 @@ impl IntEncodedWithFixedSize {
     pub const ENCODED_SIZE: usize = 8;
 }
 
-impl UseSpecializedEncodable for IntEncodedWithFixedSize {}
-impl UseSpecializedDecodable for IntEncodedWithFixedSize {}
-
-impl SpecializedEncoder<IntEncodedWithFixedSize> for opaque::Encoder {
-    fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> {
-        let start_pos = self.position();
+impl Encodable<opaque::Encoder> for IntEncodedWithFixedSize {
+    fn encode(&self, e: &mut opaque::Encoder) -> Result<(), !> {
+        let start_pos = e.position();
         for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE {
-            ((x.0 >> (i * 8)) as u8).encode(self)?;
+            ((self.0 >> (i * 8)) as u8).encode(e)?;
         }
-        let end_pos = self.position();
+        let end_pos = e.position();
         assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
         Ok(())
     }
 }
 
-impl<'a> SpecializedDecoder<IntEncodedWithFixedSize> for opaque::Decoder<'a> {
-    fn specialized_decode(&mut self) -> Result<IntEncodedWithFixedSize, Self::Error> {
+impl<'a> Decodable<opaque::Decoder<'a>> for IntEncodedWithFixedSize {
+    fn decode(decoder: &mut opaque::Decoder<'a>) -> Result<IntEncodedWithFixedSize, String> {
         let mut value: u64 = 0;
-        let start_pos = self.position();
+        let start_pos = decoder.position();
 
         for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE {
-            let byte: u8 = Decodable::decode(self)?;
+            let byte: u8 = Decodable::decode(decoder)?;
             value |= (byte as u64) << (i * 8);
         }
 
-        let end_pos = self.position();
+        let end_pos = decoder.position();
         assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
 
         Ok(IntEncodedWithFixedSize(value))
@@ -1053,8 +1013,8 @@ fn encode_query_results<'a, 'tcx, Q, E>(
 ) -> Result<(), E::Error>
 where
     Q: super::QueryDescription<TyCtxt<'tcx>> + super::QueryAccessors<TyCtxt<'tcx>>,
-    Q::Value: Encodable,
-    E: 'a + TyEncoder,
+    Q::Value: Encodable<CacheEncoder<'a, 'tcx, E>>,
+    E: 'a + OpaqueEncoder,
 {
     let _timer = tcx
         .sess
@@ -1066,15 +1026,16 @@ where
 
     state.iter_results(|results| {
         for (key, value, dep_node) in results {
-            if Q::cache_on_disk(tcx, &key, Some(&value)) {
+            if Q::cache_on_disk(tcx, &key, Some(value)) {
                 let dep_node = SerializedDepNodeIndex::new(dep_node.index());
 
                 // Record position of the cache entry.
-                query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
+                query_result_index
+                    .push((dep_node, AbsoluteBytePos::new(encoder.encoder.opaque().position())));
 
                 // Encode the type check tables with the `SerializedDepNodeIndex`
                 // as tag.
-                encoder.encode_tagged(dep_node, &value)?;
+                encoder.encode_tagged(dep_node, value)?;
             }
         }
         Ok(())
diff --git a/src/librustc_middle/ty/query/profiling_support.rs b/src/librustc_middle/ty/query/profiling_support.rs
index 0683dc02011..9b1837356e3 100644
--- a/src/librustc_middle/ty/query/profiling_support.rs
+++ b/src/librustc_middle/ty/query/profiling_support.rs
@@ -1,8 +1,9 @@
 use crate::ty::context::TyCtxt;
+use crate::ty::WithOptConstParam;
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
 use rustc_query_system::query::QueryCache;
 use rustc_query_system::query::QueryState;
@@ -154,6 +155,49 @@ impl SpecIntoSelfProfilingString for DefIndex {
     }
 }
 
+impl SpecIntoSelfProfilingString for LocalDefId {
+    fn spec_to_self_profile_string(
+        &self,
+        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+    ) -> StringId {
+        builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
+    }
+}
+
+impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
+    fn spec_to_self_profile_string(
+        &self,
+        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+    ) -> StringId {
+        // We print `WithOptConstParam` values as tuples to make them shorter
+        // and more readable, without losing information:
+        //
+        // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
+        // becomes "(foo::bar, foo::baz)" and
+        // "WithOptConstParam { did: foo::bar, const_param_did: None }"
+        // becomes "(foo::bar, _)".
+
+        let did = StringComponent::Ref(self.did.to_self_profile_string(builder));
+
+        let const_param_did = if let Some(const_param_did) = self.const_param_did {
+            let const_param_did = builder.def_id_to_string_id(const_param_did);
+            StringComponent::Ref(const_param_did)
+        } else {
+            StringComponent::Value("_")
+        };
+
+        let components = [
+            StringComponent::Value("("),
+            did,
+            StringComponent::Value(", "),
+            const_param_did,
+            StringComponent::Value(")"),
+        ];
+
+        builder.profiler.alloc_string(&components[..])
+    }
+}
+
 impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
 where
     T0: SpecIntoSelfProfilingString,
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index 310ab4f7235..05cd1ae456b 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -27,14 +27,14 @@ use std::marker::PhantomData;
 use std::ops::Range;
 use ty::util::IntTypeExt;
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub struct TypeAndMut<'tcx> {
     pub ty: Ty<'tcx>,
     pub mutbl: hir::Mutability,
 }
 
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
 #[derive(HashStable)]
 /// A "free" region `fr` can be interpreted as "some region
 /// at least as big as the scope `fr.scope`".
@@ -43,7 +43,7 @@ pub struct FreeRegion {
     pub bound_region: BoundRegion,
 }
 
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
 #[derive(HashStable)]
 pub enum BoundRegion {
     /// An anonymous region parameter for a given fn (&T)
@@ -82,7 +82,7 @@ impl BoundRegion {
 
 /// N.B., if you change this, you'll probably want to change the corresponding
 /// AST structure in `librustc_ast/ast.rs` as well.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)]
 #[derive(HashStable)]
 #[rustc_diagnostic_item = "TyKind"]
 pub enum TyKind<'tcx> {
@@ -215,7 +215,7 @@ impl TyKind<'tcx> {
 /// A type that is not publicly constructable. This prevents people from making `TyKind::Error`
 /// except through `tcx.err*()`.
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
-#[derive(RustcEncodable, RustcDecodable, HashStable)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
 pub struct DelaySpanBugEmitted(pub(super) ());
 
 // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -622,7 +622,7 @@ impl<'tcx> UpvarSubsts<'tcx> {
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub enum ExistentialPredicate<'tcx> {
     /// E.g., `Iterator`.
@@ -673,8 +673,6 @@ impl<'tcx> Binder<ExistentialPredicate<'tcx>> {
     }
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx List<ExistentialPredicate<'tcx>> {}
-
 impl<'tcx> List<ExistentialPredicate<'tcx>> {
     /// Returns the "principal `DefId`" of this set of existential predicates.
     ///
@@ -770,7 +768,7 @@ impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
 ///
 /// Trait references also appear in object types like `Foo<U>`, but in
 /// that case the `Self` parameter is absent from the substitutions.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct TraitRef<'tcx> {
     pub def_id: DefId,
@@ -828,7 +826,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
 ///
 /// The substitutions don't include the erased `Self`, only trait
 /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct ExistentialTraitRef<'tcx> {
     pub def_id: DefId,
@@ -884,7 +882,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> {
 /// erase, or otherwise "discharge" these bound vars, we change the
 /// type from `Binder<T>` to just `T` (see
 /// e.g., `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 pub struct Binder<T>(T);
 
 impl<T> Binder<T> {
@@ -1016,7 +1014,7 @@ impl<T> Binder<Option<T>> {
 
 /// Represents the projection of an associated type. In explicit UFCS
 /// form this would be written `<T as Trait<..>>::N`.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct ProjectionTy<'tcx> {
     /// The parameters of the associated item.
@@ -1086,7 +1084,7 @@ impl<'tcx> PolyGenSig<'tcx> {
 /// - `inputs`: is the list of arguments and their modes.
 /// - `output`: is the return type.
 /// - `c_variadic`: indicates whether this is a C-variadic function.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct FnSig<'tcx> {
     pub inputs_and_output: &'tcx List<Ty<'tcx>>,
@@ -1147,7 +1145,7 @@ impl<'tcx> PolyFnSig<'tcx> {
 
 pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<FnSig<'tcx>>>;
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct ParamTy {
     pub index: u32,
@@ -1172,7 +1170,7 @@ impl<'tcx> ParamTy {
     }
 }
 
-#[derive(Copy, Clone, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(Copy, Clone, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
 #[derive(HashStable)]
 pub struct ParamConst {
     pub index: u32,
@@ -1345,7 +1343,7 @@ pub type Region<'tcx> = &'tcx RegionKind;
 /// [1]: http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
 /// [2]: http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-#[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable, PartialOrd, Ord)]
+#[derive(Clone, PartialEq, Eq, Hash, Copy, TyEncodable, TyDecodable, PartialOrd, Ord)]
 pub enum RegionKind {
     /// Region bound in a type or fn declaration which will be
     /// substituted 'early' -- that is, at the same time when type
@@ -1383,32 +1381,30 @@ pub enum RegionKind {
     ReErased,
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for Region<'tcx> {}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)]
 pub struct EarlyBoundRegion {
     pub def_id: DefId,
     pub index: u32,
     pub name: Symbol,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct TyVid {
     pub index: u32,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct ConstVid<'tcx> {
     pub index: u32,
     pub phantom: PhantomData<&'tcx ()>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct IntVid {
     pub index: u32,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct FloatVid {
     pub index: u32,
 }
@@ -1425,7 +1421,7 @@ impl Atom for RegionVid {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum InferTy {
     TyVar(TyVid),
@@ -1444,14 +1440,14 @@ rustc_index::newtype_index! {
     pub struct BoundVar { .. }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct BoundTy {
     pub var: BoundVar,
     pub kind: BoundTyKind,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum BoundTyKind {
     Anon,
@@ -1465,7 +1461,7 @@ impl From<BoundVar> for BoundTy {
 }
 
 /// A `ProjectionPredicate` for an `ExistentialTraitRef`.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct ExistentialProjection<'tcx> {
     pub item_def_id: DefId,
diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs
index 866b529f35e..acd58ab7f96 100644
--- a/src/librustc_middle/ty/subst.rs
+++ b/src/librustc_middle/ty/subst.rs
@@ -1,13 +1,14 @@
 // Type substitutions.
 
 use crate::infer::canonical::Canonical;
+use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
-use rustc_serialize::{self, Decodable, Decoder, Encodable, Encoder};
+use rustc_serialize::{self, Decodable, Encodable};
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::SmallVec;
 
@@ -34,7 +35,7 @@ const TYPE_TAG: usize = 0b00;
 const REGION_TAG: usize = 0b01;
 const CONST_TAG: usize = 0b10;
 
-#[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)]
+#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)]
 pub enum GenericArgKind<'tcx> {
     Lifetime(ty::Region<'tcx>),
     Type(Ty<'tcx>),
@@ -168,14 +169,14 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
     }
 }
 
-impl<'tcx> Encodable for GenericArg<'tcx> {
-    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for GenericArg<'tcx> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.unpack().encode(e)
     }
 }
 
-impl<'tcx> Decodable for GenericArg<'tcx> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<GenericArg<'tcx>, D::Error> {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for GenericArg<'tcx> {
+    fn decode(d: &mut D) -> Result<GenericArg<'tcx>, D::Error> {
         Ok(GenericArgKind::decode(d)?.pack())
     }
 }
@@ -396,8 +397,6 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
     }
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for SubstsRef<'tcx> {}
-
 ///////////////////////////////////////////////////////////////////////////
 // Public trait `Subst`
 //
@@ -653,7 +652,7 @@ pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>;
 
 /// Stores the user-given substs to reach some fully qualified path
 /// (e.g., `<T>::Item` or `<T as Trait>::Item`).
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub struct UserSubsts<'tcx> {
     /// The substitutions for the item as given by the user.
@@ -680,7 +679,7 @@ pub struct UserSubsts<'tcx> {
 /// the impl (with the substs from `UserSubsts`) and apply those to
 /// the self type, giving `Foo<?A>`. Finally, we unify that with
 /// the self type here, which contains `?A` to be `&'static u32`
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub struct UserSelfTy<'tcx> {
     pub impl_def_id: DefId,
diff --git a/src/librustc_middle/ty/trait_def.rs b/src/librustc_middle/ty/trait_def.rs
index f93cce3f4da..86fe3ac3751 100644
--- a/src/librustc_middle/ty/trait_def.rs
+++ b/src/librustc_middle/ty/trait_def.rs
@@ -47,7 +47,7 @@ pub struct TraitDef {
 
 /// Whether this trait is treated specially by the standard library
 /// specialization lint.
-#[derive(HashStable, PartialEq, Clone, Copy, RustcEncodable, RustcDecodable)]
+#[derive(HashStable, PartialEq, Clone, Copy, TyEncodable, TyDecodable)]
 pub enum TraitSpecializationKind {
     /// The default. Specializing on this trait is not allowed.
     None,
diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs
index 07221082048..23507ac830d 100644
--- a/src/librustc_middle/ty/util.rs
+++ b/src/librustc_middle/ty/util.rs
@@ -1143,7 +1143,7 @@ pub fn needs_drop_components(
     }
 }
 
-#[derive(Copy, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub struct AlwaysRequiresDrop;
 
 /// Normalizes all opaque types in the given value, replacing them
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..4101f70b820 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;
@@ -56,6 +57,12 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.run()?;
 
     // Intern the result
+    // FIXME: since the DefId of a promoted is the DefId of its owner, this
+    // means that promoteds in statics are actually interned like statics!
+    // However, this is also currently crucial because we promote mutable
+    // non-empty slices in statics to extend their lifetime, and this
+    // ensures that they are put into a mutable allocation.
+    // For other kinds of promoteds in statics (like array initializers), this is rather silly.
     let intern_kind = match tcx.static_mutability(cid.instance.def_id()) {
         Some(m) => InternKind::Static(m),
         None if cid.promoted.is_some() => InternKind::Promoted,
@@ -213,7 +220,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 +319,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/intern.rs b/src/librustc_mir/interpret/intern.rs
index dffbc969c21..6c8ee72bc66 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -312,7 +312,8 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
     let tcx = ecx.tcx;
     let base_intern_mode = match intern_kind {
         InternKind::Static(mutbl) => InternMode::Static(mutbl),
-        // FIXME: what about array lengths, array initializers?
+        // `Constant` includes array lengths.
+        // `Promoted` includes non-`Copy` array initializers and `rustc_args_required_const` arguments.
         InternKind::Constant | InternKind::Promoted => InternMode::ConstBase,
     };
 
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/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index baa3e5e1581..324289166b9 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -86,12 +86,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
                 .skip(1)
                 .take(arg_count)
                 .map(|(local, _)| Place::from(local))
-                .filter(needs_retag)
-                .collect::<Vec<_>>();
+                .filter(needs_retag);
             // Emit their retags.
             basic_blocks[START_BLOCK].statements.splice(
                 0..0,
-                places.into_iter().map(|place| Statement {
+                places.map(|place| Statement {
                     source_info,
                     kind: StatementKind::Retag(RetagKind::FnEntry, box (place)),
                 }),
@@ -101,29 +100,24 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
         // PART 2
         // Retag return values of functions.  Also escape-to-raw the argument of `drop`.
         // We collect the return destinations because we cannot mutate while iterating.
-        let mut returns: Vec<(SourceInfo, Place<'tcx>, BasicBlock)> = Vec::new();
-        for block_data in basic_blocks.iter_mut() {
-            match block_data.terminator().kind {
-                TerminatorKind::Call { ref destination, .. } => {
-                    // Remember the return destination for later
-                    if let Some(ref destination) = destination {
-                        if needs_retag(&destination.0) {
-                            returns.push((
-                                block_data.terminator().source_info,
-                                destination.0,
-                                destination.1,
-                            ));
-                        }
+        let returns = basic_blocks
+            .iter_mut()
+            .filter_map(|block_data| {
+                match block_data.terminator().kind {
+                    TerminatorKind::Call { destination: Some(ref destination), .. }
+                        if needs_retag(&destination.0) =>
+                    {
+                        // Remember the return destination for later
+                        Some((block_data.terminator().source_info, destination.0, destination.1))
                     }
-                }
-                TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
+
                     // `Drop` is also a call, but it doesn't return anything so we are good.
-                }
-                _ => {
+                    TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => None,
                     // Not a block ending in a Call -> ignore.
+                    _ => None,
                 }
-            }
-        }
+            })
+            .collect::<Vec<_>>();
         // Now we go over the returns we collected to retag the return values.
         for (source_info, dest_place, dest_block) in returns {
             basic_blocks[dest_block].statements.insert(
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/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index 2de701284e3..66989a90244 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -12,26 +12,24 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
         for bb in basic_blocks {
             bb.expand_statements(|stmt| {
                 // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
-                if let StatementKind::Assign(box (_, ref rhs)) = stmt.kind {
-                    if let Rvalue::Aggregate(ref kind, _) = *rhs {
-                        // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
-                        if let AggregateKind::Array(_) = **kind {
-                            return None;
-                        }
-                    } else {
+                match stmt.kind {
+                    // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
+                    StatementKind::Assign(box (
+                        _,
+                        Rvalue::Aggregate(box AggregateKind::Array(_), _),
+                    )) => {
                         return None;
                     }
-                } else {
-                    return None;
+                    StatementKind::Assign(box (_, Rvalue::Aggregate(_, _))) => {}
+                    _ => return None,
                 }
 
                 let stmt = stmt.replace_nop();
                 let source_info = stmt.source_info;
                 let (lhs, kind, operands) = match stmt.kind {
-                    StatementKind::Assign(box (lhs, rvalue)) => match rvalue {
-                        Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
-                        _ => bug!(),
-                    },
+                    StatementKind::Assign(box (lhs, Rvalue::Aggregate(kind, operands))) => {
+                        (lhs, kind, operands)
+                    }
                     _ => bug!(),
                 };
 
diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs
index 5b2954dd5b0..500d66ece06 100644
--- a/src/librustc_mir/transform/instrument_coverage.rs
+++ b/src/librustc_mir/transform/instrument_coverage.rs
@@ -295,6 +295,21 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
 
         let (file_name, start_line, start_col, end_line, end_col) = self.code_region(&span);
 
+        // FIXME(richkadel): Note that `const_str()` results in the creation of an `Allocation` to
+        // hold one copy of each unique filename. It looks like that `Allocation` may translate into
+        // the creation of an `@alloc` in LLVM IR that is never actually used by runtime code.
+        //
+        // Example LLVM IR:
+        //
+        // @alloc4 = private unnamed_addr constant <{ [43 x i8] }> \
+        //   <{ [43 x i8] c"C:\\msys64\\home\\richkadel\\rust\\rust_basic.rs" }>, align 1
+        //
+        // Can I flag the alloc as something not to be added to codegen? Or somehow remove it before
+        // it gets added to the LLVM IR? Do we need some kind of reference counting to know it's
+        // not used by any runtime code?
+        //
+        // This question is moot if I convert the Call Terminators to Statements, I believe:
+        // https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/Implement.20LLVM-compatible.20source-based.20cod.20compiler-team.23278/near/206731748
         args.push(self.const_str(&file_name, inject_at));
         args.push(self.const_u32(start_line, inject_at));
         args.push(self.const_u32(start_col, inject_at));
diff --git a/src/librustc_mir/transform/match_branches.rs b/src/librustc_mir/transform/match_branches.rs
new file mode 100644
index 00000000000..74da6d5e629
--- /dev/null
+++ b/src/librustc_mir/transform/match_branches.rs
@@ -0,0 +1,93 @@
+use crate::transform::{MirPass, MirSource};
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+pub struct MatchBranchSimplification;
+
+// What's the intent of this pass?
+// If one block is found that switches between blocks which both go to the same place
+// AND both of these blocks set a similar const in their ->
+// condense into 1 block based on discriminant AND goto the destination afterwards
+
+impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+        let param_env = tcx.param_env(src.def_id());
+        let bbs = body.basic_blocks_mut();
+        'outer: for bb_idx in bbs.indices() {
+            let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
+                TerminatorKind::SwitchInt {
+                    discr: Operand::Move(ref place),
+                    switch_ty,
+                    ref targets,
+                    ref values,
+                    ..
+                } if targets.len() == 2 && values.len() == 1 => {
+                    (place, values[0], switch_ty, targets[0], targets[1])
+                }
+                // Only optimize switch int statements
+                _ => continue,
+            };
+
+            // Check that destinations are identical, and if not, then don't optimize this block
+            if &bbs[first].terminator().kind != &bbs[second].terminator().kind {
+                continue;
+            }
+
+            // Check that blocks are assignments of consts to the same place or same statement,
+            // and match up 1-1, if not don't optimize this block.
+            let first_stmts = &bbs[first].statements;
+            let scnd_stmts = &bbs[second].statements;
+            if first_stmts.len() != scnd_stmts.len() {
+                continue;
+            }
+            for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) {
+                match (&f.kind, &s.kind) {
+                    // If two statements are exactly the same just ignore them.
+                    (f_s, s_s) if f_s == s_s => (),
+
+                    (
+                        StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
+                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
+                    ) if lhs_f == lhs_s => {
+                        if let Some(f_c) = f_c.literal.try_eval_bool(tcx, param_env) {
+                            // This should also be a bool because it's writing to the same place
+                            let s_c = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
+                            if f_c != s_c {
+                                // have to check this here because f_c & s_c might have
+                                // different spans.
+                                continue;
+                            }
+                        }
+                        continue 'outer;
+                    }
+                    // If there are not exclusively assignments, then ignore this
+                    _ => continue 'outer,
+                }
+            }
+            // Take owenership of items now that we know we can optimize.
+            let discr = discr.clone();
+            let (from, first) = bbs.pick2_mut(bb_idx, first);
+
+            let new_stmts = first.statements.iter().cloned().map(|mut s| {
+                if let StatementKind::Assign(box (_, ref mut rhs)) = s.kind {
+                    if let Rvalue::Use(Operand::Constant(c)) = rhs {
+                        let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+                        let const_cmp = Operand::const_from_scalar(
+                            tcx,
+                            switch_ty,
+                            crate::interpret::Scalar::from_uint(val, size),
+                            rustc_span::DUMMY_SP,
+                        );
+                        if let Some(c) = c.literal.try_eval_bool(tcx, param_env) {
+                            let op = if c { BinOp::Eq } else { BinOp::Ne };
+                            *rhs = Rvalue::BinaryOp(op, Operand::Move(discr), const_cmp);
+                        }
+                    }
+                }
+                s
+            });
+            from.statements.extend(new_stmts);
+            from.terminator_mut().kind = first.terminator().kind.clone();
+        }
+    }
+}
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 26b4a696897..4f26f3bb459 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -29,6 +29,7 @@ pub mod generator;
 pub mod inline;
 pub mod instcombine;
 pub mod instrument_coverage;
+pub mod match_branches;
 pub mod no_landing_pads;
 pub mod nrvo;
 pub mod promote_consts;
@@ -408,6 +409,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(
@@ -437,13 +441,9 @@ fn run_optimization_passes<'tcx>(
         // with async primitives.
         &generator::StateTransform,
         &instcombine::InstCombine,
+        &match_branches::MatchBranchSimplification,
         &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 +460,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/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index c0564105701..94637bae44a 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -101,7 +101,7 @@ impl TempState {
 /// of a larger candidate.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum Candidate {
-    /// Borrow of a constant temporary.
+    /// Borrow of a constant temporary, candidate for lifetime extension.
     Ref(Location),
 
     /// Promotion of the `x` in `[x; 32]`.
diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs
index 02896d7de35..84082edd193 100644
--- a/src/librustc_mir/transform/simplify_try.rs
+++ b/src/librustc_mir/transform/simplify_try.rs
@@ -246,12 +246,14 @@ fn get_arm_identity_info<'a, 'tcx>(
         tmp_assigned_vars.insert(*r);
     }
 
-    let mut dbg_info_to_adjust = Vec::new();
-    for (i, var_info) in debug_info.iter().enumerate() {
-        if tmp_assigned_vars.contains(var_info.place.local) {
-            dbg_info_to_adjust.push(i);
-        }
-    }
+    let dbg_info_to_adjust: Vec<_> =
+        debug_info
+            .iter()
+            .enumerate()
+            .filter_map(|(i, var_info)| {
+                if tmp_assigned_vars.contains(var_info.place.local) { Some(i) } else { None }
+            })
+            .collect();
 
     Some(ArmIdentityInfo {
         local_temp_0: local_tmp_s0,
@@ -461,14 +463,14 @@ fn match_get_variant_field<'tcx>(
     stmt: &Statement<'tcx>,
 ) -> Option<(Local, Local, VarField<'tcx>, &'tcx List<PlaceElem<'tcx>>)> {
     match &stmt.kind {
-        StatementKind::Assign(box (place_into, rvalue_from)) => match rvalue_from {
-            Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)) => {
-                let local_into = place_into.as_local()?;
-                let (local_from, vf) = match_variant_field_place(*pf)?;
-                Some((local_into, local_from, vf, pf.projection))
-            }
-            _ => None,
-        },
+        StatementKind::Assign(box (
+            place_into,
+            Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)),
+        )) => {
+            let local_into = place_into.as_local()?;
+            let (local_from, vf) = match_variant_field_place(*pf)?;
+            Some((local_into, local_from, vf, pf.projection))
+        }
         _ => None,
     }
 }
@@ -479,14 +481,11 @@ fn match_get_variant_field<'tcx>(
 /// ```
 fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
     match &stmt.kind {
-        StatementKind::Assign(box (place_from, rvalue_into)) => match rvalue_into {
-            Rvalue::Use(Operand::Move(place_into)) => {
-                let local_into = place_into.as_local()?;
-                let (local_from, vf) = match_variant_field_place(*place_from)?;
-                Some((local_into, local_from, vf))
-            }
-            _ => None,
-        },
+        StatementKind::Assign(box (place_from, Rvalue::Use(Operand::Move(place_into)))) => {
+            let local_into = place_into.as_local()?;
+            let (local_from, vf) = match_variant_field_place(*place_from)?;
+            Some((local_into, local_from, vf))
+        }
         _ => None,
     }
 }
diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/src/librustc_mir/transform/uninhabited_enum_branching.rs
index e3b182b8849..4cca4d223c0 100644
--- a/src/librustc_mir/transform/uninhabited_enum_branching.rs
+++ b/src/librustc_mir/transform/uninhabited_enum_branching.rs
@@ -99,26 +99,18 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
             if let TerminatorKind::SwitchInt { values, targets, .. } =
                 &mut body.basic_blocks_mut()[bb].terminator_mut().kind
             {
-                let vals = &*values;
-                let zipped = vals.iter().zip(targets.iter());
-
-                let mut matched_values = Vec::with_capacity(allowed_variants.len());
-                let mut matched_targets = Vec::with_capacity(allowed_variants.len() + 1);
-
-                for (val, target) in zipped {
-                    if allowed_variants.contains(val) {
-                        matched_values.push(*val);
-                        matched_targets.push(*target);
-                    } else {
-                        trace!("eliminating {:?} -> {:?}", val, target);
-                    }
-                }
-
-                // handle the "otherwise" branch
-                matched_targets.push(targets.pop().unwrap());
-
-                *values = matched_values.into();
-                *targets = matched_targets;
+                // take otherwise out early
+                let otherwise = targets.pop().unwrap();
+                assert_eq!(targets.len(), values.len());
+                let mut i = 0;
+                targets.retain(|_| {
+                    let keep = allowed_variants.contains(&values[i]);
+                    i += 1;
+                    keep
+                });
+                targets.push(otherwise);
+
+                values.to_mut().retain(|var| allowed_variants.contains(var));
             } else {
                 unreachable!()
             }
diff --git a/src/librustc_mir/transform/unreachable_prop.rs b/src/librustc_mir/transform/unreachable_prop.rs
index d9f2259030f..fa362c66fb2 100644
--- a/src/librustc_mir/transform/unreachable_prop.rs
+++ b/src/librustc_mir/transform/unreachable_prop.rs
@@ -67,18 +67,13 @@ fn remove_successors<F>(
 where
     F: Fn(BasicBlock) -> bool,
 {
-    match *terminator_kind {
-        TerminatorKind::Goto { target } if predicate(target) => Some(TerminatorKind::Unreachable),
+    let terminator = match *terminator_kind {
+        TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable,
         TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
             let original_targets_len = targets.len();
             let (otherwise, targets) = targets.split_last().unwrap();
-            let retained = values
-                .iter()
-                .zip(targets.iter())
-                .filter(|(_, &t)| !predicate(t))
-                .collect::<Vec<_>>();
-            let mut values = retained.iter().map(|&(v, _)| *v).collect::<Vec<_>>();
-            let mut targets = retained.iter().map(|&(_, d)| *d).collect::<Vec<_>>();
+            let (mut values, mut targets): (Vec<_>, Vec<_>) =
+                values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip();
 
             if !predicate(*otherwise) {
                 targets.push(*otherwise);
@@ -89,20 +84,21 @@ where
             let retained_targets_len = targets.len();
 
             if targets.is_empty() {
-                Some(TerminatorKind::Unreachable)
+                TerminatorKind::Unreachable
             } else if targets.len() == 1 {
-                Some(TerminatorKind::Goto { target: targets[0] })
+                TerminatorKind::Goto { target: targets[0] }
             } else if original_targets_len != retained_targets_len {
-                Some(TerminatorKind::SwitchInt {
+                TerminatorKind::SwitchInt {
                     discr: discr.clone(),
                     switch_ty,
                     values: Cow::from(values),
                     targets,
-                })
+                }
             } else {
-                None
+                return None;
             }
         }
-        _ => None,
-    }
+        _ => return None,
+    };
+    Some(terminator)
 }
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_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index f3f3c3e33a4..215a0c7dfdf 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -10,7 +10,6 @@ use rustc_hir::lang_items;
 use rustc_hir::{GeneratorKind, HirIdMap, Node};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::Subst;
@@ -798,22 +797,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         argument_scope: region::Scope,
         ast_body: &'tcx hir::Expr<'tcx>,
     ) -> BlockAnd<()> {
-        let tcx = self.hir.tcx();
-        let attrs = tcx.codegen_fn_attrs(fn_def_id);
-        let naked = attrs.flags.contains(CodegenFnAttrFlags::NAKED);
-
         // Allocate locals for the function arguments
         for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
             let source_info =
                 SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span));
             let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info));
 
-            // Emit function argument debuginfo only for non-naked functions.
-            // See: https://github.com/rust-lang/rust/issues/42779
-            if naked {
-                continue;
-            }
-
             // If this is a simple binding pattern, give debuginfo a nice name.
             if let Some(arg) = arg_opt {
                 if let Some(ident) = arg.pat.simple_ident() {
@@ -826,6 +815,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
+        let tcx = self.hir.tcx();
         let tcx_hir = tcx.hir();
         let hir_typeck_results = self.hir.typeck_results();
 
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 55a134ae091..8e2bee26468 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 {
@@ -295,11 +318,18 @@ impl<'a> Parser<'a> {
             // want to keep their span info to improve diagnostics in these cases in a later stage.
             (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
             (true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
-            (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475)
             (true, Some(AssocOp::Add)) // `{ 42 } + 42
             // If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
             // `if x { a } else { b } && if y { c } else { d }`
-            if !self.look_ahead(1, |t| t.is_reserved_ident()) => {
+            if !self.look_ahead(1, |t| t.is_used_keyword()) => {
+                // These cases are ambiguous and can't be identified in the parser alone.
+                let sp = self.sess.source_map().start_point(self.token.span);
+                self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
+                false
+            }
+            (true, Some(AssocOp::LAnd)) => {
+                // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
+                // above due to #74233.
                 // These cases are ambiguous and can't be identified in the parser alone.
                 let sp = self.sess.source_map().start_point(self.token.span);
                 self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
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_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml
index 64af9c5f1a1..c1ec452e001 100644
--- a/src/librustc_query_system/Cargo.toml
+++ b/src/librustc_query_system/Cargo.toml
@@ -15,6 +15,7 @@ log = { package = "tracing", version = "0.1" }
 rustc-rayon-core = "0.3.0"
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_index = { path = "../librustc_index" }
 rustc_serialize = { path = "../librustc_serialize" }
 rustc_span = { path = "../librustc_span" }
diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs
index 002b0f9c165..e302784cc3e 100644
--- a/src/librustc_query_system/dep_graph/dep_node.rs
+++ b/src/librustc_query_system/dep_graph/dep_node.rs
@@ -50,7 +50,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use std::fmt;
 use std::hash::Hash;
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct DepNode<K> {
     pub kind: K,
     pub hash: Fingerprint,
@@ -152,7 +152,8 @@ impl<Ctxt: DepContext> DepNodeParams<Ctxt> for () {
 /// some independent path or string that persists between runs without
 /// the need to be mapped or unmapped. (This ensures we can serialize
 /// them even in the absence of a tcx.)
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Encodable, Decodable)]
 pub struct WorkProductId {
     hash: Fingerprint,
 }
diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs
index 04a45090b72..d70306b4869 100644
--- a/src/librustc_query_system/dep_graph/graph.rs
+++ b/src/librustc_query_system/dep_graph/graph.rs
@@ -857,7 +857,7 @@ impl<K: DepKind> DepGraph<K> {
 /// may be added -- for example, new monomorphizations -- even if
 /// nothing in P changed!). We will compare that hash against the
 /// previous hash. If it matches up, we can reuse the object file.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Encodable, Decodable)]
 pub struct WorkProduct {
     pub cgu_name: String,
     /// Saved file associated with this CGU.
diff --git a/src/librustc_query_system/dep_graph/prev.rs b/src/librustc_query_system/dep_graph/prev.rs
index 5cba64cac4b..29357ce9449 100644
--- a/src/librustc_query_system/dep_graph/prev.rs
+++ b/src/librustc_query_system/dep_graph/prev.rs
@@ -3,7 +3,7 @@ use super::{DepKind, DepNode};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Encodable, Decodable)]
 pub struct PreviousDepGraph<K: DepKind> {
     data: SerializedDepGraph<K>,
     index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
diff --git a/src/librustc_query_system/dep_graph/serialized.rs b/src/librustc_query_system/dep_graph/serialized.rs
index 4a89da23ea6..932c6d2a2f1 100644
--- a/src/librustc_query_system/dep_graph/serialized.rs
+++ b/src/librustc_query_system/dep_graph/serialized.rs
@@ -9,7 +9,7 @@ rustc_index::newtype_index! {
 }
 
 /// Data for use when recompiling the **current crate**.
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Encodable, Decodable)]
 pub struct SerializedDepGraph<K: DepKind> {
     /// The set of all DepNodes in the graph
     pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
diff --git a/src/librustc_query_system/lib.rs b/src/librustc_query_system/lib.rs
index 4bbba7befe9..db104398f16 100644
--- a/src/librustc_query_system/lib.rs
+++ b/src/librustc_query_system/lib.rs
@@ -10,6 +10,8 @@
 extern crate log;
 #[macro_use]
 extern crate rustc_data_structures;
+#[macro_use]
+extern crate rustc_macros;
 
 pub mod cache;
 pub mod dep_graph;
diff --git a/src/librustc_query_system/query/caches.rs b/src/librustc_query_system/query/caches.rs
index f0beec0a177..1839e1af45e 100644
--- a/src/librustc_query_system/query/caches.rs
+++ b/src/librustc_query_system/query/caches.rs
@@ -43,9 +43,8 @@ pub trait QueryCache: QueryStorage {
         OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R,
         OnMiss: FnOnce(Self::Key, QueryLookup<'_, CTX, Self::Key, Self::Sharded>) -> R;
 
-    fn complete<CTX: QueryContext>(
+    fn complete(
         &self,
-        tcx: CTX,
         lock_sharded_storage: &mut Self::Sharded,
         key: Self::Key,
         value: Self::Value,
@@ -112,9 +111,8 @@ impl<K: Eq + Hash, V: Clone> QueryCache for DefaultCache<K, V> {
     }
 
     #[inline]
-    fn complete<CTX: QueryContext>(
+    fn complete(
         &self,
-        _: CTX,
         lock_sharded_storage: &mut Self::Sharded,
         key: K,
         value: V,
@@ -195,9 +193,8 @@ impl<'tcx, K: Eq + Hash, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V> {
     }
 
     #[inline]
-    fn complete<CTX: QueryContext>(
+    fn complete(
         &self,
-        _: CTX,
         lock_sharded_storage: &mut Self::Sharded,
         key: K,
         value: V,
diff --git a/src/librustc_query_system/query/plumbing.rs b/src/librustc_query_system/query/plumbing.rs
index cc7d0a15703..ae042cc8081 100644
--- a/src/librustc_query_system/query/plumbing.rs
+++ b/src/librustc_query_system/query/plumbing.rs
@@ -264,7 +264,7 @@ where
     /// Completes the query by updating the query cache with the `result`,
     /// signals the waiter and forgets the JobOwner, so it won't poison the query
     #[inline(always)]
-    fn complete(self, tcx: CTX, result: C::Value, dep_node_index: DepNodeIndex) -> C::Stored {
+    fn complete(self, result: C::Value, dep_node_index: DepNodeIndex) -> C::Stored {
         // We can move out of `self` here because we `mem::forget` it below
         let key = unsafe { ptr::read(&self.key) };
         let state = self.state;
@@ -278,7 +278,7 @@ where
                 QueryResult::Started(job) => job,
                 QueryResult::Poisoned => panic!(),
             };
-            let result = state.cache.complete(tcx, &mut lock.cache, key, result, dep_node_index);
+            let result = state.cache.complete(&mut lock.cache, key, result, dep_node_index);
             (job, result)
         };
 
@@ -432,7 +432,7 @@ where
             tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
         }
 
-        return job.complete(tcx, result, dep_node_index);
+        return job.complete(result, dep_node_index);
     }
 
     let dep_node = query.to_dep_node(tcx, &key);
@@ -458,7 +458,7 @@ where
             })
         });
         if let Some((result, dep_node_index)) = loaded {
-            return job.complete(tcx, result, dep_node_index);
+            return job.complete(result, dep_node_index);
         }
     }
 
@@ -609,7 +609,7 @@ where
         }
     }
 
-    let result = job.complete(tcx, result, dep_node_index);
+    let result = job.complete(result, dep_node_index);
 
     (result, dep_node_index)
 }
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..b3746ac2db2 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -7,17 +7,18 @@ use crate::{PathResult, PathSource, Segment};
 
 use rustc_ast::ast::{self, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
 use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::FxHashSet;
 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 +34,7 @@ enum AssocSuggestion {
 crate enum MissingLifetimeSpot<'tcx> {
     Generics(&'tcx hir::Generics<'tcx>),
     HigherRanked { span: Span, span_type: ForLifetimeSpanType },
+    Static,
 }
 
 crate enum ForLifetimeSpanType {
@@ -88,6 +90,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(
@@ -162,16 +176,40 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
         let code = source.error_code(res.is_some());
         let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
 
+        let is_assoc_fn = self.self_type_is_available(span);
         // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
-        if ["this", "my"].contains(&&*item_str.as_str())
-            && self.self_value_is_available(path[0].ident.span, span)
-        {
+        if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn {
             err.span_suggestion_short(
                 span,
                 "you might have meant to use `self` here instead",
                 "self".to_string(),
                 Applicability::MaybeIncorrect,
             );
+            if !self.self_value_is_available(path[0].ident.span, span) {
+                if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
+                    &self.diagnostic_metadata.current_function
+                {
+                    let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
+                        (param.span.shrink_to_lo(), "&self, ")
+                    } else {
+                        (
+                            self.r
+                                .session
+                                .source_map()
+                                .span_through_char(*fn_span, '(')
+                                .shrink_to_hi(),
+                            "&self",
+                        )
+                    };
+                    err.span_suggestion_verbose(
+                        span,
+                        "if you meant to use `self`, you are also missing a `self` receiver \
+                         argument",
+                        sugg.to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
         }
 
         // Emit special messages for unresolved `Self` and `self`.
@@ -200,7 +238,38 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                 if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) {
                     err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
                 } else {
-                    err.span_label(*span, "this function doesn't have a `self` parameter");
+                    let doesnt = if is_assoc_fn {
+                        let (span, sugg) = fn_kind
+                            .decl()
+                            .inputs
+                            .get(0)
+                            .map(|p| (p.span.shrink_to_lo(), "&self, "))
+                            .unwrap_or_else(|| {
+                                (
+                                    self.r
+                                        .session
+                                        .source_map()
+                                        .span_through_char(*span, '(')
+                                        .shrink_to_hi(),
+                                    "&self",
+                                )
+                            });
+                        err.span_suggestion_verbose(
+                            span,
+                            "add a `self` receiver parameter to make the associated `fn` a method",
+                            sugg.to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                        "doesn't"
+                    } else {
+                        "can't"
+                    };
+                    if let Some(ident) = fn_kind.ident() {
+                        err.span_label(
+                            ident.span,
+                            &format!("this function {} have a `self` parameter", doesnt),
+                        );
+                    }
                 }
             }
             return (err, Vec::new());
@@ -339,8 +408,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 +418,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 +449,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 +589,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 +622,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 +653,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 +677,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 +755,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 +953,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 +1023,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 +1252,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                             https://doc.rust-lang.org/nomicon/hrtb.html",
                     );
                 }
+                _ => {}
             }
         }
         if nightly_options::is_nightly_build()
@@ -1224,7 +1311,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 +1326,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 +1390,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 +1425,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 +1481,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 +1501,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/Cargo.toml b/src/librustc_serialize/Cargo.toml
index 84206df50cc..939e6a59ba0 100644
--- a/src/librustc_serialize/Cargo.toml
+++ b/src/librustc_serialize/Cargo.toml
@@ -11,3 +11,6 @@ path = "lib.rs"
 [dependencies]
 indexmap = "1"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+
+[dev-dependencies]
+rustc_macros = { path = "../librustc_macros" }
diff --git a/src/librustc_serialize/collection_impls.rs b/src/librustc_serialize/collection_impls.rs
index c602de37b14..3d274cb0150 100644
--- a/src/librustc_serialize/collection_impls.rs
+++ b/src/librustc_serialize/collection_impls.rs
@@ -9,8 +9,8 @@ use std::sync::Arc;
 
 use smallvec::{Array, SmallVec};
 
-impl<A: Array<Item: Encodable>> Encodable for SmallVec<A> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
             for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?;
@@ -20,8 +20,8 @@ impl<A: Array<Item: Encodable>> Encodable for SmallVec<A> {
     }
 }
 
-impl<A: Array<Item: Decodable>> Decodable for SmallVec<A> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<SmallVec<A>, D::Error> {
+impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> {
+    fn decode(d: &mut D) -> Result<SmallVec<A>, D::Error> {
         d.read_seq(|d, len| {
             let mut vec = SmallVec::with_capacity(len);
             // FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error>
@@ -33,8 +33,8 @@ impl<A: Array<Item: Decodable>> Decodable for SmallVec<A> {
     }
 }
 
-impl<T: Encodable> Encodable for LinkedList<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
             for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?;
@@ -44,8 +44,8 @@ impl<T: Encodable> Encodable for LinkedList<T> {
     }
 }
 
-impl<T: Decodable> Decodable for LinkedList<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<LinkedList<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> {
+    fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut list = LinkedList::new();
             for i in 0..len {
@@ -56,8 +56,8 @@ impl<T: Decodable> Decodable for LinkedList<T> {
     }
 }
 
-impl<T: Encodable> Encodable for VecDeque<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
             for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?;
@@ -67,8 +67,8 @@ impl<T: Encodable> Encodable for VecDeque<T> {
     }
 }
 
-impl<T: Decodable> Decodable for VecDeque<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<VecDeque<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> {
+    fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut deque: VecDeque<T> = VecDeque::with_capacity(len);
             for i in 0..len {
@@ -79,30 +79,28 @@ impl<T: Decodable> Decodable for VecDeque<T> {
     }
 }
 
-impl<K, V> Encodable for BTreeMap<K, V>
+impl<S: Encoder, K, V> Encodable<S> for BTreeMap<K, V>
 where
-    K: Encodable + PartialEq + Ord,
-    V: Encodable,
+    K: Encodable<S> + PartialEq + Ord,
+    V: Encodable<S>,
 {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
+    fn encode(&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(())
         })
     }
 }
 
-impl<K, V> Decodable for BTreeMap<K, V>
+impl<D: Decoder, K, V> Decodable<D> for BTreeMap<K, V>
 where
-    K: Decodable + PartialEq + Ord,
-    V: Decodable,
+    K: Decodable<D> + PartialEq + Ord,
+    V: Decodable<D>,
 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
+    fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
         d.read_map(|d, len| {
             let mut map = BTreeMap::new();
             for i in 0..len {
@@ -115,27 +113,25 @@ where
     }
 }
 
-impl<T> Encodable for BTreeSet<T>
+impl<S: Encoder, T> Encodable<S> for BTreeSet<T>
 where
-    T: Encodable + PartialEq + Ord,
+    T: Encodable<S> + PartialEq + Ord,
 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&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(())
         })
     }
 }
 
-impl<T> Decodable for BTreeSet<T>
+impl<D: Decoder, T> Decodable<D> for BTreeSet<T>
 where
-    T: Decodable + PartialEq + Ord,
+    T: Decodable<D> + PartialEq + Ord,
 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
+    fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut set = BTreeSet::new();
             for i in 0..len {
@@ -146,32 +142,30 @@ where
     }
 }
 
-impl<K, V, S> Encodable for HashMap<K, V, S>
+impl<E: Encoder, K, V, S> Encodable<E> for HashMap<K, V, S>
 where
-    K: Encodable + Eq,
-    V: Encodable,
+    K: Encodable<E> + Eq,
+    V: Encodable<E>,
     S: BuildHasher,
 {
-    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+    fn encode(&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(())
         })
     }
 }
 
-impl<K, V, S> Decodable for HashMap<K, V, S>
+impl<D: Decoder, K, V, S> Decodable<D> for HashMap<K, V, S>
 where
-    K: Decodable + Hash + Eq,
-    V: Decodable,
+    K: Decodable<D> + Hash + Eq,
+    V: Decodable<D>,
     S: BuildHasher + Default,
 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
+    fn decode(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
         d.read_map(|d, len| {
             let state = Default::default();
             let mut map = HashMap::with_capacity_and_hasher(len, state);
@@ -185,29 +179,37 @@ where
     }
 }
 
-impl<T, S> Encodable for HashSet<T, S>
+impl<E: Encoder, T, S> Encodable<E> for HashSet<T, S>
 where
-    T: Encodable + Eq,
+    T: Encodable<E> + Eq,
     S: BuildHasher,
 {
-    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+    fn encode(&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(())
         })
     }
 }
 
-impl<T, S> Decodable for HashSet<T, S>
+impl<E: Encoder, T, S> Encodable<E> for &HashSet<T, S>
 where
-    T: Decodable + Hash + Eq,
+    T: Encodable<E> + Eq,
+    S: BuildHasher,
+{
+    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+        (**self).encode(s)
+    }
+}
+
+impl<D: Decoder, T, S> Decodable<D> for HashSet<T, S>
+where
+    T: Decodable<D> + Hash + Eq,
     S: BuildHasher + Default,
 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, S>, D::Error> {
+    fn decode(d: &mut D) -> Result<HashSet<T, S>, D::Error> {
         d.read_seq(|d, len| {
             let state = Default::default();
             let mut set = HashSet::with_capacity_and_hasher(len, state);
@@ -219,32 +221,30 @@ where
     }
 }
 
-impl<K, V, S> Encodable for indexmap::IndexMap<K, V, S>
+impl<E: Encoder, K, V, S> Encodable<E> for indexmap::IndexMap<K, V, S>
 where
-    K: Encodable + Hash + Eq,
-    V: Encodable,
+    K: Encodable<E> + Hash + Eq,
+    V: Encodable<E>,
     S: BuildHasher,
 {
-    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+    fn encode(&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(())
         })
     }
 }
 
-impl<K, V, S> Decodable for indexmap::IndexMap<K, V, S>
+impl<D: Decoder, K, V, S> Decodable<D> for indexmap::IndexMap<K, V, S>
 where
-    K: Decodable + Hash + Eq,
-    V: Decodable,
+    K: Decodable<D> + Hash + Eq,
+    V: Decodable<D>,
     S: BuildHasher + Default,
 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, D::Error> {
+    fn decode(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, D::Error> {
         d.read_map(|d, len| {
             let state = Default::default();
             let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
@@ -258,29 +258,27 @@ where
     }
 }
 
-impl<T, S> Encodable for indexmap::IndexSet<T, S>
+impl<E: Encoder, T, S> Encodable<E> for indexmap::IndexSet<T, S>
 where
-    T: Encodable + Hash + Eq,
+    T: Encodable<E> + Hash + Eq,
     S: BuildHasher,
 {
-    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+    fn encode(&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(())
         })
     }
 }
 
-impl<T, S> Decodable for indexmap::IndexSet<T, S>
+impl<D: Decoder, T, S> Decodable<D> for indexmap::IndexSet<T, S>
 where
-    T: Decodable + Hash + Eq,
+    T: Decodable<D> + Hash + Eq,
     S: BuildHasher + Default,
 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<indexmap::IndexSet<T, S>, D::Error> {
+    fn decode(d: &mut D) -> Result<indexmap::IndexSet<T, S>, D::Error> {
         d.read_seq(|d, len| {
             let state = Default::default();
             let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
@@ -292,8 +290,8 @@ where
     }
 }
 
-impl<T: Encodable> Encodable for Rc<[T]> {
-    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> {
+    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
         s.emit_seq(self.len(), |s| {
             for (index, e) in self.iter().enumerate() {
                 s.emit_seq_elt(index, |s| e.encode(s))?;
@@ -303,8 +301,8 @@ impl<T: Encodable> Encodable for Rc<[T]> {
     }
 }
 
-impl<T: Decodable> Decodable for Rc<[T]> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Rc<[T]>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> {
+    fn decode(d: &mut D) -> Result<Rc<[T]>, D::Error> {
         d.read_seq(|d, len| {
             let mut vec = Vec::with_capacity(len);
             for index in 0..len {
@@ -315,8 +313,8 @@ impl<T: Decodable> Decodable for Rc<[T]> {
     }
 }
 
-impl<T: Encodable> Encodable for Arc<[T]> {
-    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> {
+    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
         s.emit_seq(self.len(), |s| {
             for (index, e) in self.iter().enumerate() {
                 s.emit_seq_elt(index, |s| e.encode(s))?;
@@ -326,8 +324,8 @@ impl<T: Encodable> Encodable for Arc<[T]> {
     }
 }
 
-impl<T: Decodable> Decodable for Arc<[T]> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Arc<[T]>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> {
+    fn decode(d: &mut D) -> Result<Arc<[T]>, D::Error> {
         d.read_seq(|d, len| {
             let mut vec = Vec::with_capacity(len);
             for index in 0..len {
diff --git a/src/librustc_serialize/json.rs b/src/librustc_serialize/json.rs
index 820ebdc9baa..6c8965aa2e3 100644
--- a/src/librustc_serialize/json.rs
+++ b/src/librustc_serialize/json.rs
@@ -47,17 +47,17 @@
 //!
 //! Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via
 //! the serialization API.
-//! To be able to encode a piece of data, it must implement the `serialize::RustcEncodable` trait.
-//! To be able to decode a piece of data, it must implement the `serialize::RustcDecodable` trait.
+//! To be able to encode a piece of data, it must implement the `serialize::Encodable` trait.
+//! To be able to decode a piece of data, it must implement the `serialize::Decodable` trait.
 //! The Rust compiler provides an annotation to automatically generate the code for these traits:
-//! `#[derive(RustcDecodable, RustcEncodable)]`
+//! `#[derive(Decodable, Encodable)]`
 //!
 //! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects.
 //! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value.
 //! A `json::Json` value can be encoded as a string or buffer using the functions described above.
 //! You can also use the `json::Encoder` object, which implements the `Encoder` trait.
 //!
-//! When using `ToJson` the `RustcEncodable` trait implementation is not mandatory.
+//! When using `ToJson` the `Encodable` trait implementation is not mandatory.
 //!
 //! # Examples of use
 //!
@@ -68,29 +68,28 @@
 //!
 //! ```rust
 //! # #![feature(rustc_private)]
+//! use rustc_macros::{Decodable, Encodable};
 //! use rustc_serialize::json;
 //!
 //! // Automatically generate `Decodable` and `Encodable` trait implementations
-//! #[derive(RustcDecodable, RustcEncodable)]
+//! #[derive(Decodable, Encodable)]
 //! pub struct TestStruct  {
 //!     data_int: u8,
 //!     data_str: String,
 //!     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
@@ -102,6 +101,7 @@
 //!
 //! ```rust
 //! # #![feature(rustc_private)]
+//! use rustc_macros::Encodable;
 //! use rustc_serialize::json::{self, ToJson, Json};
 //!
 //! // A custom data structure
@@ -117,35 +117,34 @@
 //!     }
 //! }
 //!
-//! // Only generate `RustcEncodable` trait implementation
-//! #[derive(RustcEncodable)]
+//! // Only generate `Encodable` trait implementation
+//! #[derive(Encodable)]
 //! pub struct ComplexNumRecord {
 //!     uid: u8,
 //!     dsc: String,
 //!     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
 //!
 //! ```rust
 //! # #![feature(rustc_private)]
+//! use rustc_macros::Decodable;
 //! use std::collections::BTreeMap;
 //! use rustc_serialize::json::{self, Json, ToJson};
 //!
-//! // Only generate `RustcDecodable` trait implementation
-//! #[derive(RustcDecodable)]
+//! // Only generate `Decodable` trait implementation
+//! #[derive(Decodable)]
 //! pub struct TestStruct {
 //!     data_int: u8,
 //!     data_str: String,
@@ -164,19 +163,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::*;
@@ -298,7 +295,7 @@ pub fn error_str(error: ErrorCode) -> &'static str {
 }
 
 /// Shortcut function to decode a JSON `&str` into an object
-pub fn decode<T: crate::Decodable>(s: &str) -> DecodeResult<T> {
+pub fn decode<T: crate::Decodable<Decoder>>(s: &str) -> DecodeResult<T> {
     let json = match from_str(s) {
         Ok(x) => x,
         Err(e) => return Err(ParseError(e)),
@@ -309,7 +306,9 @@ pub fn decode<T: crate::Decodable>(s: &str) -> DecodeResult<T> {
 }
 
 /// Shortcut function to encode a `T` into a JSON `String`
-pub fn encode<T: crate::Encodable>(object: &T) -> Result<string::String, EncoderError> {
+pub fn encode<T: for<'r> crate::Encodable<Encoder<'r>>>(
+    object: &T,
+) -> Result<string::String, EncoderError> {
     let mut s = String::new();
     {
         let mut encoder = Encoder::new(&mut s);
@@ -1150,8 +1149,8 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> {
     }
 }
 
-impl Encodable for Json {
-    fn encode<E: crate::Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+impl<E: crate::Encoder> Encodable<E> for Json {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         match *self {
             Json::I64(v) => v.encode(e),
             Json::U64(v) => v.encode(e),
@@ -1269,34 +1268,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 +1403,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 +1430,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 +1535,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.
@@ -2747,7 +2732,7 @@ impl<'a> fmt::Display for PrettyJson<'a> {
     }
 }
 
-impl<'a, T: Encodable> fmt::Display for AsJson<'a, T> {
+impl<'a, T: for<'r> Encodable<Encoder<'r>>> fmt::Display for AsJson<'a, T> {
     /// Encodes a json value into a string
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut shim = FormatShim { inner: f };
@@ -2767,7 +2752,7 @@ impl<'a, T> AsPrettyJson<'a, T> {
     }
 }
 
-impl<'a, T: Encodable> fmt::Display for AsPrettyJson<'a, T> {
+impl<'a, T: for<'x> Encodable<PrettyEncoder<'x>>> fmt::Display for AsPrettyJson<'a, T> {
     /// Encodes a json value into a string
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut shim = FormatShim { inner: f };
diff --git a/src/librustc_serialize/lib.rs b/src/librustc_serialize/lib.rs
index 3dc3e783820..265b3b95e95 100644
--- a/src/librustc_serialize/lib.rs
+++ b/src/librustc_serialize/lib.rs
@@ -10,7 +10,6 @@ Core encoding and decoding interfaces.
     test(attr(allow(unused_variables), deny(warnings)))
 )]
 #![feature(box_syntax)]
-#![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
@@ -19,9 +18,6 @@ Core encoding and decoding interfaces.
 
 pub use self::serialize::{Decodable, Decoder, Encodable, Encoder};
 
-pub use self::serialize::{SpecializationError, SpecializedDecoder, SpecializedEncoder};
-pub use self::serialize::{UseSpecializedDecodable, UseSpecializedEncodable};
-
 mod collection_impls;
 mod serialize;
 
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_serialize/serialize.rs b/src/librustc_serialize/serialize.rs
index 29c5737ad89..c0e23b89a60 100644
--- a/src/librustc_serialize/serialize.rs
+++ b/src/librustc_serialize/serialize.rs
@@ -4,7 +4,6 @@
 Core encoding and decoding interfaces.
 */
 
-use std::any;
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::marker::PhantomData;
@@ -380,282 +379,155 @@ pub trait Decoder {
     fn error(&mut self, err: &str) -> Self::Error;
 }
 
-pub trait Encodable {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error>;
-}
-
-pub trait Decodable: Sized {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
-}
-
-impl Encodable for usize {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_usize(*self)
-    }
-}
-
-impl Decodable for usize {
-    fn decode<D: Decoder>(d: &mut D) -> Result<usize, D::Error> {
-        d.read_usize()
-    }
-}
-
-impl Encodable for u8 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u8(*self)
-    }
-}
-
-impl Decodable for u8 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<u8, D::Error> {
-        d.read_u8()
-    }
-}
-
-impl Encodable for u16 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u16(*self)
-    }
-}
-
-impl Decodable for u16 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<u16, D::Error> {
-        d.read_u16()
-    }
-}
-
-impl Encodable for u32 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u32(*self)
-    }
+/// Trait for types that can be serialized
+///
+/// This can be implemented using the `Encodable`, `TyEncodable` and
+/// `MetadataEncodable` macros.
+///
+/// * `Encodable` should be used in crates that don't depend on
+///   `rustc_middle`.
+/// * `MetadataEncodable` is used in `rustc_metadata` for types that contain
+///   `rustc_metadata::rmeta::Lazy`.
+/// * `TyEncodable` should be used for types that are only serialized in crate
+///   metadata or the incremental cache. This is most types in `rustc_middle`.
+pub trait Encodable<S: Encoder> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error>;
 }
 
-impl Decodable for u32 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<u32, D::Error> {
-        d.read_u32()
-    }
-}
+/// Trait for types that can be deserialized
+///
+/// This can be implemented using the `Decodable`, `TyDecodable` and
+/// `MetadataDecodable` macros.
+///
+/// * `Decodable` should be used in crates that don't depend on
+///   `rustc_middle`.
+/// * `MetadataDecodable` is used in `rustc_metadata` for types that contain
+///   `rustc_metadata::rmeta::Lazy`.
+/// * `TyDecodable` should be used for types that are only serialized in crate
+///   metadata or the incremental cache. This is most types in `rustc_middle`.
+pub trait Decodable<D: Decoder>: Sized {
+    fn decode(d: &mut D) -> Result<Self, D::Error>;
+}
+
+macro_rules! direct_serialize_impls {
+    ($($ty:ident $emit_method:ident $read_method:ident),*) => {
+        $(
+            impl<S: Encoder> Encodable<S> for $ty {
+                fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+                    s.$emit_method(*self)
+                }
+            }
 
-impl Encodable for ::std::num::NonZeroU32 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+            impl<D: Decoder> Decodable<D> for $ty {
+                fn decode(d: &mut D) -> Result<$ty, D::Error> {
+                    d.$read_method()
+                }
+            }
+        )*
+    }
+}
+
+direct_serialize_impls! {
+    usize emit_usize read_usize,
+    u8 emit_u8 read_u8,
+    u16 emit_u16 read_u16,
+    u32 emit_u32 read_u32,
+    u64 emit_u64 read_u64,
+    u128 emit_u128 read_u128,
+    isize emit_isize read_isize,
+    i8 emit_i8 read_i8,
+    i16 emit_i16 read_i16,
+    i32 emit_i32 read_i32,
+    i64 emit_i64 read_i64,
+    i128 emit_i128 read_i128,
+    f32 emit_f32 read_f32,
+    f64 emit_f64 read_f64,
+    bool emit_bool read_bool,
+    char emit_char read_char
+}
+
+impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_u32(self.get())
     }
 }
 
-impl Decodable for ::std::num::NonZeroU32 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
+impl<D: Decoder> Decodable<D> for ::std::num::NonZeroU32 {
+    fn decode(d: &mut D) -> Result<Self, D::Error> {
         d.read_u32().map(|d| ::std::num::NonZeroU32::new(d).unwrap())
     }
 }
 
-impl Encodable for u64 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u64(*self)
-    }
-}
-
-impl Decodable for u64 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<u64, D::Error> {
-        d.read_u64()
-    }
-}
-
-impl Encodable for u128 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u128(*self)
-    }
-}
-
-impl Decodable for u128 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<u128, D::Error> {
-        d.read_u128()
-    }
-}
-
-impl Encodable for isize {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_isize(*self)
-    }
-}
-
-impl Decodable for isize {
-    fn decode<D: Decoder>(d: &mut D) -> Result<isize, D::Error> {
-        d.read_isize()
-    }
-}
-
-impl Encodable for i8 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_i8(*self)
-    }
-}
-
-impl Decodable for i8 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<i8, D::Error> {
-        d.read_i8()
-    }
-}
-
-impl Encodable for i16 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_i16(*self)
-    }
-}
-
-impl Decodable for i16 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<i16, D::Error> {
-        d.read_i16()
-    }
-}
-
-impl Encodable for i32 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_i32(*self)
-    }
-}
-
-impl Decodable for i32 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<i32, D::Error> {
-        d.read_i32()
-    }
-}
-
-impl Encodable for i64 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_i64(*self)
-    }
-}
-
-impl Decodable for i64 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<i64, D::Error> {
-        d.read_i64()
-    }
-}
-
-impl Encodable for i128 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_i128(*self)
-    }
-}
-
-impl Decodable for i128 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<i128, D::Error> {
-        d.read_i128()
+impl<S: Encoder> Encodable<S> for str {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_str(self)
     }
 }
 
-impl Encodable for str {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for &str {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_str(self)
     }
 }
 
-impl Encodable for String {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for String {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_str(&self[..])
     }
 }
 
-impl Decodable for String {
-    fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
+impl<D: Decoder> Decodable<D> for String {
+    fn decode(d: &mut D) -> Result<String, D::Error> {
         Ok(d.read_str()?.into_owned())
     }
 }
 
-impl Encodable for f32 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_f32(*self)
-    }
-}
-
-impl Decodable for f32 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<f32, D::Error> {
-        d.read_f32()
-    }
-}
-
-impl Encodable for f64 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_f64(*self)
-    }
-}
-
-impl Decodable for f64 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<f64, D::Error> {
-        d.read_f64()
-    }
-}
-
-impl Encodable for bool {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_bool(*self)
-    }
-}
-
-impl Decodable for bool {
-    fn decode<D: Decoder>(d: &mut D) -> Result<bool, D::Error> {
-        d.read_bool()
-    }
-}
-
-impl Encodable for char {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_char(*self)
-    }
-}
-
-impl Decodable for char {
-    fn decode<D: Decoder>(d: &mut D) -> Result<char, D::Error> {
-        d.read_char()
-    }
-}
-
-impl Encodable for () {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for () {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_unit()
     }
 }
 
-impl Decodable for () {
-    fn decode<D: Decoder>(d: &mut D) -> Result<(), D::Error> {
+impl<D: Decoder> Decodable<D> for () {
+    fn decode(d: &mut D) -> Result<(), D::Error> {
         d.read_nil()
     }
 }
 
-impl<T> Encodable for PhantomData<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T> Encodable<S> for PhantomData<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_unit()
     }
 }
 
-impl<T> Decodable for PhantomData<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<PhantomData<T>, D::Error> {
+impl<D: Decoder, T> Decodable<D> for PhantomData<T> {
+    fn decode(d: &mut D) -> Result<PhantomData<T>, D::Error> {
         d.read_nil()?;
         Ok(PhantomData)
     }
 }
 
-impl<T: Decodable> Decodable for Box<[T]> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Box<[T]>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> {
+    fn decode(d: &mut D) -> Result<Box<[T]>, D::Error> {
         let v: Vec<T> = Decodable::decode(d)?;
         Ok(v.into_boxed_slice())
     }
 }
 
-impl<T: Encodable> Encodable for Rc<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for Rc<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         (**self).encode(s)
     }
 }
 
-impl<T: Decodable> Decodable for Rc<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Rc<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<T> {
+    fn decode(d: &mut D) -> Result<Rc<T>, D::Error> {
         Ok(Rc::new(Decodable::decode(d)?))
     }
 }
 
-impl<T: Encodable> Encodable for [T] {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
             for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?
@@ -665,8 +537,8 @@ impl<T: Encodable> Encodable for [T] {
     }
 }
 
-impl<T: Encodable> Encodable for Vec<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
             for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?
@@ -676,8 +548,8 @@ impl<T: Encodable> Encodable for Vec<T> {
     }
 }
 
-impl<T: Decodable> Decodable for Vec<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Vec<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
+    fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut v = Vec::with_capacity(len);
             for i in 0..len {
@@ -688,8 +560,8 @@ impl<T: Decodable> Decodable for Vec<T> {
     }
 }
 
-impl Encodable for [u8; 20] {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for [u8; 20] {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
             for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?
@@ -699,8 +571,8 @@ impl Encodable for [u8; 20] {
     }
 }
 
-impl Decodable for [u8; 20] {
-    fn decode<D: Decoder>(d: &mut D) -> Result<[u8; 20], D::Error> {
+impl<D: Decoder> Decodable<D> for [u8; 20] {
+    fn decode(d: &mut D) -> Result<[u8; 20], D::Error> {
         d.read_seq(|d, len| {
             assert!(len == 20);
             let mut v = [0u8; 20];
@@ -712,11 +584,11 @@ impl Decodable for [u8; 20] {
     }
 }
 
-impl<'a, T: Encodable> Encodable for Cow<'a, [T]>
+impl<'a, S: Encoder, T: Encodable<S>> Encodable<S> for Cow<'a, [T]>
 where
     [T]: ToOwned<Owned = Vec<T>>,
 {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
             for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?
@@ -726,11 +598,11 @@ where
     }
 }
 
-impl<T: Decodable + ToOwned> Decodable for Cow<'static, [T]>
+impl<D: Decoder, T: Decodable<D> + ToOwned> Decodable<D> for Cow<'static, [T]>
 where
     [T]: ToOwned<Owned = Vec<T>>,
 {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> {
+    fn decode(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> {
         d.read_seq(|d, len| {
             let mut v = Vec::with_capacity(len);
             for i in 0..len {
@@ -741,8 +613,8 @@ where
     }
 }
 
-impl<T: Encodable> Encodable for Option<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_option(|s| match *self {
             None => s.emit_option_none(),
             Some(ref v) => s.emit_option_some(|s| v.encode(s)),
@@ -750,14 +622,14 @@ impl<T: Encodable> Encodable for Option<T> {
     }
 }
 
-impl<T: Decodable> Decodable for Option<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Option<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> {
+    fn decode(d: &mut D) -> Result<Option<T>, D::Error> {
         d.read_option(|d, b| if b { Ok(Some(Decodable::decode(d)?)) } else { Ok(None) })
     }
 }
 
-impl<T1: Encodable, T2: Encodable> Encodable for Result<T1, T2> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_enum("Result", |s| match *self {
             Ok(ref v) => {
                 s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s)))
@@ -769,8 +641,8 @@ impl<T1: Encodable, T2: Encodable> Encodable for Result<T1, T2> {
     }
 }
 
-impl<T1: Decodable, T2: Decodable> Decodable for Result<T1, T2> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Result<T1, T2>, D::Error> {
+impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> {
+    fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> {
         d.read_enum("Result", |d| {
             d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr {
                 0 => Ok(Ok(d.read_enum_variant_arg(0, |d| T1::decode(d))?)),
@@ -806,9 +678,9 @@ macro_rules! count {
 macro_rules! tuple {
     () => ();
     ( $($name:ident,)+ ) => (
-        impl<$($name:Decodable),+> Decodable for ($($name,)+) {
+        impl<D: Decoder, $($name: Decodable<D>),+> Decodable<D> for ($($name,)+) {
             #[allow(non_snake_case)]
-            fn decode<D: Decoder>(d: &mut D) -> Result<($($name,)+), D::Error> {
+            fn decode(d: &mut D) -> Result<($($name,)+), D::Error> {
                 let len: usize = count!($($name)+);
                 d.read_tuple(len, |d| {
                     let mut i = 0;
@@ -819,9 +691,9 @@ macro_rules! tuple {
                 })
             }
         }
-        impl<$($name:Encodable),+> Encodable for ($($name,)+) {
+        impl<S: Encoder, $($name: Encodable<S>),+> Encodable<S> for ($($name,)+) {
             #[allow(non_snake_case)]
-            fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+            fn encode(&self, s: &mut S) -> Result<(), S::Error> {
                 let ($(ref $name,)+) = *self;
                 let mut n = 0;
                 $(let $name = $name; n += 1;)+
@@ -838,33 +710,33 @@ macro_rules! tuple {
 
 tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
 
-impl Encodable for path::Path {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for path::Path {
+    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
         self.to_str().unwrap().encode(e)
     }
 }
 
-impl Encodable for path::PathBuf {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for path::PathBuf {
+    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
         path::Path::encode(self, e)
     }
 }
 
-impl Decodable for path::PathBuf {
-    fn decode<D: Decoder>(d: &mut D) -> Result<path::PathBuf, D::Error> {
+impl<D: Decoder> Decodable<D> for path::PathBuf {
+    fn decode(d: &mut D) -> Result<path::PathBuf, D::Error> {
         let bytes: String = Decodable::decode(d)?;
         Ok(path::PathBuf::from(bytes))
     }
 }
 
-impl<T: Encodable + Copy> Encodable for Cell<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S> + Copy> Encodable<S> for Cell<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         self.get().encode(s)
     }
 }
 
-impl<T: Decodable + Copy> Decodable for Cell<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Cell<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D> + Copy> Decodable<D> for Cell<T> {
+    fn decode(d: &mut D) -> Result<Cell<T>, D::Error> {
         Ok(Cell::new(Decodable::decode(d)?))
     }
 }
@@ -874,136 +746,37 @@ impl<T: Decodable + Copy> Decodable for Cell<T> {
 // `encoder.error("attempting to Encode borrowed RefCell")`
 // from `encode` when `try_borrow` returns `None`.
 
-impl<T: Encodable> Encodable for RefCell<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for RefCell<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         self.borrow().encode(s)
     }
 }
 
-impl<T: Decodable> Decodable for RefCell<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<RefCell<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for RefCell<T> {
+    fn decode(d: &mut D) -> Result<RefCell<T>, D::Error> {
         Ok(RefCell::new(Decodable::decode(d)?))
     }
 }
 
-impl<T: Encodable> Encodable for Arc<T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for Arc<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         (**self).encode(s)
     }
 }
 
-impl<T: Decodable> Decodable for Arc<T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Arc<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<T> {
+    fn decode(d: &mut D) -> Result<Arc<T>, D::Error> {
         Ok(Arc::new(Decodable::decode(d)?))
     }
 }
 
-// ___________________________________________________________________________
-// Specialization-based interface for multi-dispatch Encodable/Decodable.
-
-/// Implement this trait on your `{Encodable,Decodable}::Error` types
-/// to override the default panic behavior for missing specializations.
-pub trait SpecializationError {
-    /// Creates an error for a missing method specialization.
-    /// Defaults to panicking with type, trait & method names.
-    /// `S` is the encoder/decoder state type,
-    /// `T` is the type being encoded/decoded, and
-    /// the arguments are the names of the trait
-    /// and method that should've been overridden.
-    fn not_found<S, T: ?Sized>(trait_name: &'static str, method_name: &'static str) -> Self;
-}
-
-impl<E> SpecializationError for E {
-    default fn not_found<S, T: ?Sized>(trait_name: &'static str, method_name: &'static str) -> E {
-        panic!(
-            "missing specialization: `<{} as {}<{}>>::{}` not overridden",
-            any::type_name::<S>(),
-            trait_name,
-            any::type_name::<T>(),
-            method_name
-        );
-    }
-}
-
-/// Implement this trait on encoders, with `T` being the type
-/// you want to encode (employing `UseSpecializedEncodable`),
-/// using a strategy specific to the encoder.
-pub trait SpecializedEncoder<T: ?Sized + UseSpecializedEncodable>: Encoder {
-    /// Encode the value in a manner specific to this encoder state.
-    fn specialized_encode(&mut self, value: &T) -> Result<(), Self::Error>;
-}
-
-impl<E: Encoder, T: ?Sized + UseSpecializedEncodable> SpecializedEncoder<T> for E {
-    default fn specialized_encode(&mut self, value: &T) -> Result<(), E::Error> {
-        value.default_encode(self)
-    }
-}
-
-/// Implement this trait on decoders, with `T` being the type
-/// you want to decode (employing `UseSpecializedDecodable`),
-/// using a strategy specific to the decoder.
-pub trait SpecializedDecoder<T: UseSpecializedDecodable>: Decoder {
-    /// Decode a value in a manner specific to this decoder state.
-    fn specialized_decode(&mut self) -> Result<T, Self::Error>;
-}
-
-impl<D: Decoder, T: UseSpecializedDecodable> SpecializedDecoder<T> for D {
-    default fn specialized_decode(&mut self) -> Result<T, D::Error> {
-        T::default_decode(self)
-    }
-}
-
-/// Implement this trait on your type to get an `Encodable`
-/// implementation which goes through `SpecializedEncoder`.
-pub trait UseSpecializedEncodable {
-    /// Defaults to returning an error (see `SpecializationError`).
-    fn default_encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
-        Err(E::Error::not_found::<E, Self>("SpecializedEncoder", "specialized_encode"))
-    }
-}
-
-impl<T: ?Sized + UseSpecializedEncodable> Encodable for T {
-    default fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
-        E::specialized_encode(e, self)
-    }
-}
-
-/// Implement this trait on your type to get an `Decodable`
-/// implementation which goes through `SpecializedDecoder`.
-pub trait UseSpecializedDecodable: Sized {
-    /// Defaults to returning an error (see `SpecializationError`).
-    fn default_decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
-        Err(D::Error::not_found::<D, Self>("SpecializedDecoder", "specialized_decode"))
-    }
-}
-
-impl<T: UseSpecializedDecodable> Decodable for T {
-    default fn decode<D: Decoder>(d: &mut D) -> Result<T, D::Error> {
-        D::specialized_decode(d)
-    }
-}
-
-// Can't avoid specialization for &T and Box<T> impls,
-// as proxy impls on them are blankets that conflict
-// with the Encodable and Decodable impls above,
-// which only have `default` on their methods
-// for this exact reason.
-// May be fixable in a simpler fashion via the
-// more complex lattice model for specialization.
-impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
-    }
-}
-impl<T: ?Sized + Encodable> UseSpecializedEncodable for Box<T> {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder, T: ?Sized + Encodable<S>> Encodable<S> for Box<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         (**self).encode(s)
     }
 }
-impl<T: Decodable> UseSpecializedDecodable for Box<T> {
-    fn default_decode<D: Decoder>(d: &mut D) -> Result<Box<T>, D::Error> {
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {
+    fn decode(d: &mut D) -> Result<Box<T>, D::Error> {
         Ok(box Decodable::decode(d)?)
     }
 }
-impl<'a, T: Decodable> UseSpecializedDecodable for &'a T {}
-impl<'a, T: Decodable> UseSpecializedDecodable for &'a [T] {}
diff --git a/src/librustc_serialize/tests/json.rs b/src/librustc_serialize/tests/json.rs
index 59c481edbca..e3a823127d9 100644
--- a/src/librustc_serialize/tests/json.rs
+++ b/src/librustc_serialize/tests/json.rs
@@ -9,6 +9,7 @@ use json::{
     from_str, DecodeResult, Decoder, DecoderError, Encoder, EncoderError, Json, JsonEvent, Parser,
     StackElement,
 };
+use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::json;
 use rustc_serialize::{Decodable, Encodable};
 
@@ -17,7 +18,7 @@ use std::io::prelude::*;
 use std::string;
 use Animal::*;
 
-#[derive(RustcDecodable, Eq, PartialEq, Debug)]
+#[derive(Decodable, Eq, PartialEq, Debug)]
 struct OptionData {
     opt: Option<usize>,
 }
@@ -48,20 +49,20 @@ fn test_decode_option_malformed() {
     );
 }
 
-#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(PartialEq, Encodable, Decodable, Debug)]
 enum Animal {
     Dog,
     Frog(string::String, isize),
 }
 
-#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(PartialEq, Encodable, Decodable, Debug)]
 struct Inner {
     a: (),
     b: usize,
     c: Vec<string::String>,
 }
 
-#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(PartialEq, Encodable, Decodable, Debug)]
 struct Outer {
     inner: Vec<Inner>,
 }
@@ -568,7 +569,7 @@ fn test_decode_struct() {
     );
 }
 
-#[derive(RustcDecodable)]
+#[derive(Decodable)]
 struct FloatStruct {
     f: f64,
     a: Vec<f64>,
@@ -616,7 +617,7 @@ fn test_multiline_errors() {
     assert_eq!(from_str("{\n  \"foo\":\n \"bar\""), Err(SyntaxError(EOFWhileParsingObject, 3, 8)));
 }
 
-#[derive(RustcDecodable)]
+#[derive(Decodable)]
 #[allow(dead_code)]
 struct DecodeStruct {
     x: f64,
@@ -624,12 +625,12 @@ struct DecodeStruct {
     z: string::String,
     w: Vec<DecodeStruct>,
 }
-#[derive(RustcDecodable)]
+#[derive(Decodable)]
 enum DecodeEnum {
     A(f64),
     B(string::String),
 }
-fn check_err<T: Decodable>(to_parse: &'static str, expected: DecoderError) {
+fn check_err<T: Decodable<Decoder>>(to_parse: &'static str, expected: DecoderError) {
     let res: DecodeResult<T> = match from_str(to_parse) {
         Err(e) => Err(ParseError(e)),
         Ok(json) => Decodable::decode(&mut Decoder::new(json)),
@@ -933,7 +934,7 @@ fn test_prettyencoder_indent_level_param() {
 #[test]
 fn test_hashmap_with_enum_key() {
     use std::collections::HashMap;
-    #[derive(RustcEncodable, Eq, Hash, PartialEq, RustcDecodable, Debug)]
+    #[derive(Encodable, Eq, Hash, PartialEq, Decodable, Debug)]
     enum Enum {
         Foo,
         #[allow(dead_code)]
@@ -1254,7 +1255,7 @@ fn test_to_json() {
 #[test]
 fn test_encode_hashmap_with_arbitrary_key() {
     use std::collections::HashMap;
-    #[derive(PartialEq, Eq, Hash, RustcEncodable)]
+    #[derive(PartialEq, Eq, Hash, Encodable)]
     struct ArbitraryType(usize);
     let mut hm: HashMap<ArbitraryType, bool> = HashMap::new();
     hm.insert(ArbitraryType(1), true);
diff --git a/src/librustc_serialize/tests/opaque.rs b/src/librustc_serialize/tests/opaque.rs
index c8273917007..13b3676a56c 100644
--- a/src/librustc_serialize/tests/opaque.rs
+++ b/src/librustc_serialize/tests/opaque.rs
@@ -1,10 +1,11 @@
 #![allow(rustc::internal)]
 
+use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{Decoder, Encoder};
 use rustc_serialize::{Decodable, Encodable};
 use std::fmt::Debug;
 
-#[derive(PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
 struct Struct {
     a: (),
     b: u8,
@@ -27,11 +28,13 @@ struct Struct {
     q: Option<u32>,
 }
 
-fn check_round_trip<T: Encodable + Decodable + PartialEq + Debug>(values: Vec<T>) {
+fn check_round_trip<T: Encodable<Encoder> + for<'a> Decodable<Decoder<'a>> + PartialEq + Debug>(
+    values: Vec<T>,
+) {
     let mut encoder = Encoder::new(Vec::new());
 
     for value in &values {
-        Encodable::encode(&value, &mut encoder).unwrap();
+        Encodable::encode(value, &mut encoder).unwrap();
     }
 
     let data = encoder.into_inner();
@@ -225,7 +228,7 @@ fn test_struct() {
     }]);
 }
 
-#[derive(PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
 enum Enum {
     Variant1,
     Variant2(usize, f32),
diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml
index 35c227df850..cb6626d0f4b 100644
--- a/src/librustc_session/Cargo.toml
+++ b/src/librustc_session/Cargo.toml
@@ -12,6 +12,7 @@ path = "lib.rs"
 bitflags = "1.2.1"
 getopts = "0.2"
 log = { package = "tracing", version = "0.1" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_target = { path = "../librustc_target" }
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index 9fcdd46539c..c26c9bde3ee 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -39,7 +39,7 @@ pub struct Config {
 }
 
 bitflags! {
-    #[derive(Default, RustcEncodable, RustcDecodable)]
+    #[derive(Default, Encodable, Decodable)]
     pub struct SanitizerSet: u8 {
         const ADDRESS = 1 << 0;
         const LEAK    = 1 << 1;
@@ -194,7 +194,8 @@ impl SwitchWithOptPath {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Encodable, Decodable)]
 pub enum SymbolManglingVersion {
     Legacy,
     V0,
@@ -209,7 +210,8 @@ pub enum DebugInfo {
     Full,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Encodable, Decodable)]
 pub enum OutputType {
     Bitcode,
     Assembly,
@@ -672,7 +674,7 @@ pub enum EntryFnType {
 
 impl_stable_hash_via_hash!(EntryFnType);
 
-#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
 pub enum CrateType {
     Executable,
     Dylib,
diff --git a/src/librustc_session/lib.rs b/src/librustc_session/lib.rs
index be9d2e7be27..c2ea141a06f 100644
--- a/src/librustc_session/lib.rs
+++ b/src/librustc_session/lib.rs
@@ -3,6 +3,8 @@
 
 #[macro_use]
 extern crate bitflags;
+#[macro_use]
+extern crate rustc_macros;
 
 pub mod cgu_reuse_tracker;
 pub mod utils;
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_session/search_paths.rs b/src/librustc_session/search_paths.rs
index 4ff06acaa1f..e12364b7dac 100644
--- a/src/librustc_session/search_paths.rs
+++ b/src/librustc_session/search_paths.rs
@@ -33,7 +33,7 @@ impl SearchPathFile {
     }
 }
 
-#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
 pub enum PathKind {
     Native,
     Crate,
diff --git a/src/librustc_session/utils.rs b/src/librustc_session/utils.rs
index b97308c22cb..15447c01d1e 100644
--- a/src/librustc_session/utils.rs
+++ b/src/librustc_session/utils.rs
@@ -10,7 +10,7 @@ impl Session {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub enum NativeLibKind {
     /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included
     /// when linking a final binary, but not when archiving an rlib.
diff --git a/src/librustc_span/def_id.rs b/src/librustc_span/def_id.rs
index a874f81868f..aae778217d3 100644
--- a/src/librustc_span/def_id.rs
+++ b/src/librustc_span/def_id.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::AtomicRef;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable_Generic;
-use rustc_serialize::{Decoder, Encoder};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::borrow::Borrow;
 use std::fmt;
 
@@ -84,13 +84,14 @@ impl fmt::Display for CrateNum {
 
 /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx.
 /// Therefore, make sure to include the context when encode a `CrateNum`.
-impl rustc_serialize::UseSpecializedEncodable for CrateNum {
-    fn default_encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_u32(self.as_u32())
+impl<E: Encoder> Encodable<E> for CrateNum {
+    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+        s.emit_u32(self.as_u32())
     }
 }
-impl rustc_serialize::UseSpecializedDecodable for CrateNum {
-    fn default_decode<D: Decoder>(d: &mut D) -> Result<CrateNum, D::Error> {
+
+impl<D: Decoder> Decodable<D> for CrateNum {
+    default fn decode(d: &mut D) -> Result<CrateNum, D::Error> {
         Ok(CrateNum::from_u32(d.read_u32()?))
     }
 }
@@ -104,8 +105,8 @@ impl ::std::fmt::Debug for CrateNum {
     }
 }
 
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, RustcEncodable, RustcDecodable)]
-#[derive(HashStable_Generic)]
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct DefPathHash(pub Fingerprint);
 
 impl Borrow<Fingerprint> for DefPathHash {
@@ -120,16 +121,26 @@ rustc_index::newtype_index! {
     /// particular definition. It should really be considered an interned
     /// shorthand for a particular DefPath.
     pub struct DefIndex {
-        DEBUG_FORMAT = "DefIndex({})",
+        ENCODABLE = custom // (only encodable in metadata)
 
+        DEBUG_FORMAT = "DefIndex({})",
         /// The crate root is always assigned index 0 by the AST Map code,
         /// thanks to `NodeCollector::new`.
         const CRATE_DEF_INDEX = 0,
     }
 }
 
-impl rustc_serialize::UseSpecializedEncodable for DefIndex {}
-impl rustc_serialize::UseSpecializedDecodable for DefIndex {}
+impl<E: Encoder> Encodable<E> for DefIndex {
+    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
+        panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>());
+    }
+}
+
+impl<D: Decoder> Decodable<D> for DefIndex {
+    default fn decode(_: &mut D) -> Result<DefIndex, D::Error> {
+        panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>());
+    }
+}
 
 /// A `DefId` identifies a particular *definition*, by combining a crate
 /// index and a def index.
@@ -168,19 +179,24 @@ impl DefId {
     }
 }
 
-impl rustc_serialize::UseSpecializedEncodable for DefId {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        let krate = u64::from(self.krate.as_u32());
-        let index = u64::from(self.index.as_u32());
-        s.emit_u64((krate << 32) | index)
+impl<E: Encoder> Encodable<E> for DefId {
+    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+        s.emit_struct("DefId", 2, |s| {
+            s.emit_struct_field("krate", 0, |s| self.krate.encode(s))?;
+
+            s.emit_struct_field("index", 1, |s| self.index.encode(s))
+        })
     }
 }
-impl rustc_serialize::UseSpecializedDecodable for DefId {
-    fn default_decode<D: Decoder>(d: &mut D) -> Result<DefId, D::Error> {
-        let def_id = d.read_u64()?;
-        let krate = CrateNum::from_u32((def_id >> 32) as u32);
-        let index = DefIndex::from_u32((def_id & 0xffffffff) as u32);
-        Ok(DefId { krate, index })
+
+impl<D: Decoder> Decodable<D> for DefId {
+    default fn decode(d: &mut D) -> Result<DefId, D::Error> {
+        d.read_struct("DefId", 2, |d| {
+            Ok(DefId {
+                krate: d.read_struct_field("krate", 0, Decodable::decode)?,
+                index: d.read_struct_field("index", 1, Decodable::decode)?,
+            })
+        })
     }
 }
 
@@ -239,8 +255,17 @@ impl fmt::Debug for LocalDefId {
     }
 }
 
-impl rustc_serialize::UseSpecializedEncodable for LocalDefId {}
-impl rustc_serialize::UseSpecializedDecodable for LocalDefId {}
+impl<E: Encoder> Encodable<E> for LocalDefId {
+    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+        self.to_def_id().encode(s)
+    }
+}
+
+impl<D: Decoder> Decodable<D> for LocalDefId {
+    fn decode(d: &mut D) -> Result<LocalDefId, D::Error> {
+        DefId::decode(d).map(|d| d.expect_local())
+    }
+}
 
 impl<CTX: HashStableContext> HashStable<CTX> for DefId {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
diff --git a/src/librustc_span/edition.rs b/src/librustc_span/edition.rs
index b1ac7f04321..4d0c92f51d7 100644
--- a/src/librustc_span/edition.rs
+++ b/src/librustc_span/edition.rs
@@ -5,7 +5,7 @@ use std::str::FromStr;
 use rustc_macros::HashStable_Generic;
 
 /// The edition of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable, Eq)]
+#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, Decodable, Eq)]
 #[derive(HashStable_Generic)]
 pub enum Edition {
     // editions must be kept in order, oldest to newest
diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs
index f52b2195c2f..e8f4606b518 100644
--- a/src/librustc_span/hygiene.rs
+++ b/src/librustc_span/hygiene.rs
@@ -34,16 +34,14 @@ use log::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_macros::HashStable_Generic;
-use rustc_serialize::{
-    Decodable, Decoder, Encodable, Encoder, UseSpecializedDecodable, UseSpecializedEncodable,
-};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
 
 /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct SyntaxContext(u32);
 
-#[derive(Debug, RustcEncodable, RustcDecodable, Clone)]
+#[derive(Debug, Encodable, Decodable, Clone)]
 pub struct SyntaxContextData {
     outer_expn: ExpnId,
     outer_transparency: Transparency,
@@ -62,7 +60,7 @@ pub struct ExpnId(u32);
 
 /// A property of a macro expansion that determines how identifiers
 /// produced by that expansion are resolved.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
 #[derive(HashStable_Generic)]
 pub enum Transparency {
     /// Identifier produced by a transparent expansion is always resolved at call-site.
@@ -664,7 +662,7 @@ impl Span {
 
 /// A subset of properties from both macro definition and macro call available through global data.
 /// Avoid using this if you have access to the original definition or call structures.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct ExpnData {
     // --- The part unique to each expansion.
     /// The kind of this expansion - macro or compiler desugaring.
@@ -766,7 +764,7 @@ impl ExpnData {
 }
 
 /// Expansion kind.
-#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum ExpnKind {
     /// No expansion, aka root expansion. Only `ExpnId::root()` has this kind.
     Root,
@@ -794,7 +792,7 @@ impl ExpnKind {
 }
 
 /// The kind of macro invocation or definition.
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum MacroKind {
     /// A bang macro `foo!()`.
@@ -830,7 +828,7 @@ impl MacroKind {
 }
 
 /// The kind of AST transform.
-#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum AstPass {
     StdImports,
     TestHarness,
@@ -848,7 +846,7 @@ impl AstPass {
 }
 
 /// The kind of compiler desugaring.
-#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
 pub enum DesugaringKind {
     /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`.
     /// However, we do not want to blame `c` for unreachability but rather say that `i`
@@ -867,7 +865,7 @@ pub enum DesugaringKind {
 }
 
 /// A location in the desugaring of a `for` loop
-#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
 pub enum ForLoopLoc {
     Head,
     IntoIter,
@@ -888,9 +886,6 @@ impl DesugaringKind {
     }
 }
 
-impl UseSpecializedEncodable for ExpnId {}
-impl UseSpecializedDecodable for ExpnId {}
-
 #[derive(Default)]
 pub struct HygieneEncodeContext {
     /// All `SyntaxContexts` for which we have written `SyntaxContextData` into crate metadata.
@@ -1137,6 +1132,7 @@ pub fn for_all_expns_in<E, F: FnMut(u32, ExpnId, &ExpnData) -> Result<(), E>>(
     }
     Ok(())
 }
+
 pub fn for_all_data<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Result<(), E>>(
     mut f: F,
 ) -> Result<(), E> {
@@ -1147,6 +1143,18 @@ pub fn for_all_data<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Res
     Ok(())
 }
 
+impl<E: Encoder> Encodable<E> for ExpnId {
+    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
+        panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::<E>());
+    }
+}
+
+impl<D: Decoder> Decodable<D> for ExpnId {
+    default fn decode(_: &mut D) -> Result<Self, D::Error> {
+        panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::<D>());
+    }
+}
+
 pub fn for_all_expn_data<E, F: FnMut(u32, &ExpnData) -> Result<(), E>>(mut f: F) -> Result<(), E> {
     let all_data = HygieneData::with(|data| data.expn_data.clone());
     for (i, data) in all_data.into_iter().enumerate() {
@@ -1218,5 +1226,14 @@ impl<'a> ExpnDataDecodeMode<'a, Box<dyn FnOnce(CrateNum) -> &'a HygieneDecodeCon
     }
 }
 
-impl UseSpecializedEncodable for SyntaxContext {}
-impl UseSpecializedDecodable for SyntaxContext {}
+impl<E: Encoder> Encodable<E> for SyntaxContext {
+    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
+        panic!("cannot encode `SyntaxContext` with `{}`", std::any::type_name::<E>());
+    }
+}
+
+impl<D: Decoder> Decodable<D> for SyntaxContext {
+    default fn decode(_: &mut D) -> Result<Self, D::Error> {
+        panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>());
+    }
+}
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index 697d88ad063..c654dade2ab 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -15,8 +15,7 @@
 #![feature(option_expect_none)]
 #![feature(refcell_take)]
 
-// FIXME(#56935): Work around ICEs during cross-compilation.
-#[allow(unused)]
+#[macro_use]
 extern crate rustc_macros;
 
 use rustc_data_structures::AtomicRef;
@@ -105,8 +104,8 @@ scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
 //
 // FIXME: We should use this enum or something like it to get rid of the
 // use of magic `/rust/1.x/...` paths across the board.
-#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)]
-#[derive(HashStable_Generic)]
+#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Decodable, Encodable)]
 pub enum RealFileName {
     Named(PathBuf),
     /// For de-virtualized paths (namely paths into libstd that have been mapped
@@ -152,8 +151,8 @@ impl RealFileName {
 }
 
 /// Differentiates between real files and common virtual files.
-#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)]
-#[derive(HashStable_Generic)]
+#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Decodable, Encodable)]
 pub enum FileName {
     Real(RealFileName),
     /// Call to `quote!`.
@@ -333,7 +332,7 @@ impl Ord for Span {
 ///   the error, and would be rendered with `^^^`.
 /// - They can have a *label*. In this case, the label is written next
 ///   to the mark in the snippet when we render.
-#[derive(Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
 pub struct MultiSpan {
     primary_spans: Vec<Span>,
     span_labels: Vec<(Span, String)>,
@@ -698,23 +697,22 @@ impl Default for Span {
     }
 }
 
-impl rustc_serialize::UseSpecializedEncodable for Span {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<E: Encoder> Encodable<E> for Span {
+    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
         let span = self.data();
         s.emit_struct("Span", 2, |s| {
             s.emit_struct_field("lo", 0, |s| span.lo.encode(s))?;
-
             s.emit_struct_field("hi", 1, |s| span.hi.encode(s))
         })
     }
 }
-
-impl rustc_serialize::UseSpecializedDecodable for Span {
-    fn default_decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
-        d.read_struct("Span", 2, |d| {
+impl<D: Decoder> Decodable<D> for Span {
+    default fn decode(s: &mut D) -> Result<Span, D::Error> {
+        s.read_struct("Span", 2, |d| {
             let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
             let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
-            Ok(Span::with_root_ctxt(lo, hi))
+
+            Ok(Span::new(lo, hi, SyntaxContext::root()))
         })
     }
 }
@@ -889,7 +887,7 @@ impl From<Vec<Span>> for MultiSpan {
 }
 
 /// Identifies an offset of a multi-byte character in a `SourceFile`.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
 pub struct MultiByteChar {
     /// The absolute offset of the character in the `SourceMap`.
     pub pos: BytePos,
@@ -898,7 +896,7 @@ pub struct MultiByteChar {
 }
 
 /// Identifies an offset of a non-narrow character in a `SourceFile`.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
 pub enum NonNarrowChar {
     /// Represents a zero-width character.
     ZeroWidth(BytePos),
@@ -960,7 +958,7 @@ impl Sub<BytePos> for NonNarrowChar {
 }
 
 /// Identifies an offset of a character that was normalized away from `SourceFile`.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
 pub struct NormalizedPos {
     /// The absolute offset of the character in the `SourceMap`.
     pub pos: BytePos,
@@ -1012,7 +1010,7 @@ impl ExternalSource {
 #[derive(Debug)]
 pub struct OffsetOverflowError;
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub enum SourceFileHashAlgorithm {
     Md5,
     Sha1,
@@ -1033,8 +1031,8 @@ impl FromStr for SourceFileHashAlgorithm {
 rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm);
 
 /// The hash of the on-disk source file used for debug info.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
-#[derive(HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct SourceFileHash {
     pub kind: SourceFileHashAlgorithm,
     value: [u8; 20],
@@ -1113,8 +1111,8 @@ pub struct SourceFile {
     pub cnum: CrateNum,
 }
 
-impl Encodable for SourceFile {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for SourceFile {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_struct("SourceFile", 8, |s| {
             s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
             s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
@@ -1183,8 +1181,8 @@ impl Encodable for SourceFile {
     }
 }
 
-impl Decodable for SourceFile {
-    fn decode<D: Decoder>(d: &mut D) -> Result<SourceFile, D::Error> {
+impl<D: Decoder> Decodable<D> for SourceFile {
+    fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
         d.read_struct("SourceFile", 8, |d| {
             let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
             let name_was_remapped: bool =
@@ -1585,14 +1583,14 @@ impl Sub for BytePos {
     }
 }
 
-impl Encodable for BytePos {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_u32(self.0)
     }
 }
 
-impl Decodable for BytePos {
-    fn decode<D: Decoder>(d: &mut D) -> Result<BytePos, D::Error> {
+impl<D: rustc_serialize::Decoder> Decodable<D> for BytePos {
+    fn decode(d: &mut D) -> Result<BytePos, D::Error> {
         Ok(BytePos(d.read_u32()?))
     }
 }
diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs
index e062c7766e7..29e589057b5 100644
--- a/src/librustc_span/source_map.rs
+++ b/src/librustc_span/source_map.rs
@@ -75,7 +75,7 @@ pub mod monotonic {
     impl<T> !DerefMut for MonotonicVec<T> {}
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, Copy, HashStable_Generic)]
 pub struct Spanned<T> {
     pub node: T,
     pub span: Span,
@@ -118,7 +118,7 @@ impl FileLoader for RealFileLoader {
 // This is a `SourceFile` identifier that is used to correlate `SourceFile`s between
 // subsequent compilation sessions (which is something we need to do during
 // incremental compilation).
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
 pub struct StableSourceFileId(u128);
 
 // FIXME: we need a more globally consistent approach to the problem solved by
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index caa6de09664..7843c04f255 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -5,9 +5,8 @@
 use rustc_arena::DroplessArena;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
-use rustc_macros::{symbols, HashStable_Generic};
+use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use rustc_serialize::{UseSpecializedDecodable, UseSpecializedEncodable};
 
 use std::cmp::{Ord, PartialEq, PartialOrd};
 use std::fmt;
@@ -1192,7 +1191,7 @@ symbols! {
     }
 }
 
-#[derive(Copy, Clone, Eq, HashStable_Generic)]
+#[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)]
 pub struct Ident {
     pub name: Symbol,
     pub span: Span,
@@ -1289,26 +1288,6 @@ impl fmt::Display for Ident {
     }
 }
 
-impl UseSpecializedEncodable for Ident {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_struct("Ident", 2, |s| {
-            s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
-            s.emit_struct_field("span", 1, |s| self.span.encode(s))
-        })
-    }
-}
-
-impl UseSpecializedDecodable for Ident {
-    fn default_decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
-        d.read_struct("Ident", 2, |d| {
-            Ok(Ident {
-                name: d.read_struct_field("name", 0, Decodable::decode)?,
-                span: d.read_struct_field("span", 1, Decodable::decode)?,
-            })
-        })
-    }
-}
-
 /// This is the most general way to print identifiers.
 /// AST pretty-printer is used as a fallback for turning AST structures into token streams for
 /// proc macros. Additionally, proc macros may stringify their input and expect it survive the
@@ -1452,15 +1431,15 @@ impl fmt::Display for Symbol {
     }
 }
 
-impl Encodable for Symbol {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<S: Encoder> Encodable<S> for Symbol {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         self.with(|string| s.emit_str(string))
     }
 }
 
-impl Decodable for Symbol {
+impl<D: Decoder> Decodable<D> for Symbol {
     #[inline]
-    fn decode<D: Decoder>(d: &mut D) -> Result<Symbol, D::Error> {
+    fn decode(d: &mut D) -> Result<Symbol, D::Error> {
         Ok(Symbol::intern(&d.read_str()?))
     }
 }
@@ -1549,7 +1528,7 @@ pub mod sym {
     use super::Symbol;
     use std::convert::TryInto;
 
-    symbols!();
+    define_symbols!();
 
     // Used from a macro in `librustc_feature/accepted.rs`
     pub use super::kw::MacroRules as macro_rules;
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index b3e5f5c0c74..4b565dd246f 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -235,7 +235,7 @@ pub enum Endian {
 }
 
 /// Size of a type in bytes.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
 #[derive(HashStable_Generic)]
 pub struct Size {
     raw: u64,
@@ -358,7 +358,7 @@ impl AddAssign for Size {
 }
 
 /// Alignment of a type in bytes (always a power of two).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
 #[derive(HashStable_Generic)]
 pub struct Align {
     pow2: u8,
@@ -415,7 +415,7 @@ impl Align {
 }
 
 /// A pair of alignments, ABI-mandated and preferred.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
 #[derive(HashStable_Generic)]
 pub struct AbiAndPrefAlign {
     pub abi: Align,
diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs
index ccec17817d3..c22644bf813 100644
--- a/src/librustc_target/asm/mod.rs
+++ b/src/librustc_target/asm/mod.rs
@@ -13,7 +13,7 @@ macro_rules! def_reg_class {
             $class:ident,
         )*
     }) => {
-        #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
+        #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
         #[allow(non_camel_case_types)]
         pub enum $arch_regclass {
             $($class,)*
@@ -62,7 +62,7 @@ macro_rules! def_regs {
         )*
     }) => {
         #[allow(unreachable_code)]
-        #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
+        #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
         #[allow(non_camel_case_types)]
         pub enum $arch_reg {
             $($reg,)*
@@ -163,7 +163,7 @@ pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
 pub enum InlineAsmArch {
     X86,
     X86_64,
@@ -193,17 +193,7 @@ impl FromStr for InlineAsmArch {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    RustcEncodable,
-    RustcDecodable,
-    Debug,
-    Eq,
-    PartialEq,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
 pub enum InlineAsmReg {
     X86(X86InlineAsmReg),
     Arm(ArmInlineAsmReg),
@@ -293,17 +283,7 @@ impl InlineAsmReg {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    RustcEncodable,
-    RustcDecodable,
-    Debug,
-    Eq,
-    PartialEq,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
 pub enum InlineAsmRegClass {
     X86(X86InlineAsmRegClass),
     Arm(ArmInlineAsmRegClass),
@@ -429,17 +409,7 @@ impl InlineAsmRegClass {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    RustcEncodable,
-    RustcDecodable,
-    Debug,
-    Eq,
-    PartialEq,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
 pub enum InlineAsmRegOrRegClass {
     Reg(InlineAsmReg),
     RegClass(InlineAsmRegClass),
diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs
index 1d0dc660ee6..62df63ceb1e 100644
--- a/src/librustc_target/lib.rs
+++ b/src/librustc_target/lib.rs
@@ -16,8 +16,7 @@
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
 
-// FIXME(#56935): Work around ICEs during cross-compilation.
-#[allow(unused)]
+#[macro_use]
 extern crate rustc_macros;
 
 #[macro_use]
diff --git a/src/librustc_target/spec/abi.rs b/src/librustc_target/spec/abi.rs
index a5c874bb4ac..1e45739ca22 100644
--- a/src/librustc_target/spec/abi.rs
+++ b/src/librustc_target/spec/abi.rs
@@ -5,8 +5,8 @@ use rustc_macros::HashStable_Generic;
 #[cfg(test)]
 mod tests;
 
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Clone, Copy, Debug)]
-#[derive(HashStable_Generic)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum Abi {
     // N.B., this ordering MUST match the AbiDatas array below.
     // (This is ensured by the test indices_are_correct().)
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 961a438fd23..fa29ff3f8d8 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -161,7 +161,7 @@ flavor_mappings! {
     ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
 pub enum PanicStrategy {
     Unwind,
     Abort,
@@ -185,7 +185,7 @@ impl ToJson for PanicStrategy {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub enum RelroLevel {
     Full,
     Partial,
@@ -229,7 +229,7 @@ impl ToJson for RelroLevel {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub enum MergeFunctions {
     Disabled,
     Trampolines,
@@ -1734,7 +1734,7 @@ impl ToJson for Target {
 }
 
 /// Either a target triple string or a path to a JSON file.
-#[derive(PartialEq, Clone, Debug, Hash, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Clone, Debug, Hash, Encodable, Decodable)]
 pub enum TargetTriple {
     TargetTriple(String),
     TargetPath(PathBuf),
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_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 717b7e2fe57..316181ce7d4 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -324,8 +324,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
 
         let ty = ty.super_fold_with(self);
         match ty.kind {
-            ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
-                // (*)
+            ty::Opaque(def_id, substs) => {
                 // Only normalize `impl Trait` after type-checking, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty,
@@ -353,9 +352,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
             }
 
             ty::Projection(ref data) if !data.has_escaping_bound_vars() => {
-                // (*)
-
-                // (*) This is kind of hacky -- we need to be able to
+                // This is kind of hacky -- we need to be able to
                 // handle normalization within binders because
                 // otherwise we wind up a need to normalize when doing
                 // trait matching (since you can have a trait
diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs
index 59fa4c1598d..93652329305 100644
--- a/src/librustc_trait_selection/traits/query/normalize.rs
+++ b/src/librustc_trait_selection/traits/query/normalize.rs
@@ -101,8 +101,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
 
         let ty = ty.super_fold_with(self);
         match ty.kind {
-            ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
-                // (*)
+            ty::Opaque(def_id, substs) => {
                 // Only normalize `impl Trait` after type-checking, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty,
@@ -140,8 +139,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
             }
 
             ty::Projection(ref data) if !data.has_escaping_bound_vars() => {
-                // (*)
-                // (*) This is kind of hacky -- we need to be able to
+                // This is kind of hacky -- we need to be able to
                 // handle normalization within binders because
                 // otherwise we wind up a need to normalize when doing
                 // trait matching (since you can have a trait
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 79d2f104a52..3093ddbeaf1 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -489,10 +489,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             kind,
         );
 
+        let unordered = sess.features_untracked().const_generics;
         let kind_ord = match kind {
             "lifetime" => ParamKindOrd::Lifetime,
             "type" => ParamKindOrd::Type,
-            "constant" => ParamKindOrd::Const,
+            "constant" => ParamKindOrd::Const { unordered },
             // It's more concise to match on the string representation, though it means
             // the match is non-exhaustive.
             _ => bug!("invalid generic parameter kind {}", kind),
@@ -500,17 +501,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let arg_ord = match arg {
             GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
             GenericArg::Type(_) => ParamKindOrd::Type,
-            GenericArg::Const(_) => ParamKindOrd::Const,
+            GenericArg::Const(_) => ParamKindOrd::Const { unordered },
         };
 
-        // This note will be true as long as generic parameters are strictly ordered by their kind.
-        let (first, last) =
-            if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
-        err.note(&format!("{} arguments must be provided before {} arguments", first, last));
-
-        if let Some(help) = help {
-            err.help(help);
+        // This note is only true when generic parameters are strictly ordered by their kind.
+        if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
+            let (first, last) =
+                if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
+            err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+            if let Some(help) = help {
+                err.help(help);
+            }
         }
+
         err.emit();
     }
 
@@ -672,7 +675,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                                         ParamKindOrd::Type
                                                     }
                                                     GenericParamDefKind::Const => {
-                                                        ParamKindOrd::Const
+                                                        ParamKindOrd::Const {
+                                                            unordered: tcx
+                                                                .sess
+                                                                .features_untracked()
+                                                                .const_generics,
+                                                        }
                                                     }
                                                 },
                                                 param,
@@ -1615,6 +1623,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         span: Span,
         trait_bounds: &[hir::PolyTraitRef<'_>],
         lifetime: &hir::Lifetime,
+        borrowed: bool,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
 
@@ -1829,15 +1838,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     self.ast_region_to_region(lifetime, None)
                 } else {
                     self.re_infer(None, span).unwrap_or_else(|| {
-                        // FIXME: these can be redundant with E0106, but not always.
-                        struct_span_err!(
+                        let mut err = struct_span_err!(
                             tcx.sess,
                             span,
                             E0228,
                             "the lifetime bound for this object type cannot be deduced \
                              from context; please supply an explicit bound"
-                        )
-                        .emit();
+                        );
+                        if borrowed {
+                            // We will have already emitted an error E0106 complaining about a
+                            // missing named lifetime in `&dyn Trait`, so we elide this one.
+                            err.delay_as_bug();
+                        } else {
+                            err.emit();
+                        }
                         tcx.lifetimes.re_static
                     })
                 }
@@ -2865,6 +2879,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// Parses the programmer's textual representation of a type into our
     /// internal notion of a type.
     pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
+        self.ast_ty_to_ty_inner(ast_ty, false)
+    }
+
+    /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
+    /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
+    fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> {
         debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", ast_ty.hir_id, ast_ty, ast_ty.kind);
 
         let tcx = self.tcx();
@@ -2877,7 +2897,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             hir::TyKind::Rptr(ref region, ref mt) => {
                 let r = self.ast_region_to_region(region, None);
                 debug!("ast_ty_to_ty: r={:?}", r);
-                let t = self.ast_ty_to_ty(&mt.ty);
+                let t = self.ast_ty_to_ty_inner(&mt.ty, true);
                 tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
             }
             hir::TyKind::Never => tcx.types.never,
@@ -2895,7 +2915,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 ))
             }
             hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
-                self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
+                self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
             }
             hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
                 debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
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/demand.rs b/src/librustc_typeck/check/demand.rs
index 258c5b77df2..4ea76a4a9e2 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
         self.suggest_missing_await(err, expr, expected, expr_ty);
+        self.suggest_missing_parentheses(err, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
     }
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 106df847a05..9078dc40041 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -649,6 +649,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     self.assemble_inherent_impl_for_primitive(lang_def_id);
                 }
             }
+            ty::Array(_, _) => {
+                let lang_def_id = lang_items.array_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl }) => {
                 let (lang_def_id1, lang_def_id2) = match mutbl {
                     hir::Mutability::Not => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3d58fb30d91..6957b6b2a05 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);
@@ -5395,6 +5401,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) {
+        let sp = self.tcx.sess.source_map().start_point(expr.span);
+        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
+        }
+    }
+
     fn note_need_for_fn_pointer(
         &self,
         err: &mut DiagnosticBuilder<'_>,
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/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs
index 93ee87f6c57..cd7429f166f 100644
--- a/src/librustc_typeck/coherence/inherent_impls.rs
+++ b/src/librustc_typeck/coherence/inherent_impls.rs
@@ -112,6 +112,16 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     item.span,
                 );
             }
+            ty::Array(_, _) => {
+                self.check_primitive_impl(
+                    def_id,
+                    lang_items.array_impl(),
+                    None,
+                    "array",
+                    "[T; N]",
+                    item.span,
+                );
+            }
             ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not })
                 if matches!(inner.kind, ty::Slice(_)) =>
             {
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 7b1dd5b11ed..801d06e6101 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1083,25 +1083,37 @@ impl Clean<TypeKind> for hir::def::DefKind {
 
 impl Clean<Item> for hir::TraitItem<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
+        let local_did = cx.tcx.hir().local_def_id(self.hir_id);
         let inner = match self.kind {
             hir::TraitItemKind::Const(ref ty, default) => {
                 AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e)))
             }
             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                MethodItem((sig, &self.generics, body, None).clean(cx))
+                let mut m = (sig, &self.generics, body, None).clean(cx);
+                if m.header.constness == hir::Constness::Const
+                    && !is_min_const_fn(cx.tcx, local_did.to_def_id())
+                {
+                    m.header.constness = hir::Constness::NotConst;
+                }
+                MethodItem(m)
             }
             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
                 let (generics, decl) = enter_impl_trait(cx, || {
                     (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                 });
                 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
-                TyMethodItem(TyMethod { header: sig.header, decl, generics, all_types, ret_types })
+                let mut t = TyMethod { header: sig.header, decl, generics, all_types, ret_types };
+                if t.header.constness == hir::Constness::Const
+                    && !is_min_const_fn(cx.tcx, local_did.to_def_id())
+                {
+                    t.header.constness = hir::Constness::NotConst;
+                }
+                TyMethodItem(t)
             }
             hir::TraitItemKind::Type(ref bounds, ref default) => {
                 AssocTypeItem(bounds.clean(cx), default.clean(cx))
             }
         };
-        let local_did = cx.tcx.hir().local_def_id(self.hir_id);
         Item {
             name: Some(self.ident.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -1117,12 +1129,19 @@ impl Clean<Item> for hir::TraitItem<'_> {
 
 impl Clean<Item> for hir::ImplItem<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
+        let local_did = cx.tcx.hir().local_def_id(self.hir_id);
         let inner = match self.kind {
             hir::ImplItemKind::Const(ref ty, expr) => {
                 AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr)))
             }
             hir::ImplItemKind::Fn(ref sig, body) => {
-                MethodItem((sig, &self.generics, body, Some(self.defaultness)).clean(cx))
+                let mut m = (sig, &self.generics, body, Some(self.defaultness)).clean(cx);
+                if m.header.constness == hir::Constness::Const
+                    && !is_min_const_fn(cx.tcx, local_did.to_def_id())
+                {
+                    m.header.constness = hir::Constness::NotConst;
+                }
+                MethodItem(m)
             }
             hir::ImplItemKind::TyAlias(ref ty) => {
                 let type_ = ty.clean(cx);
@@ -1130,7 +1149,6 @@ impl Clean<Item> for hir::ImplItem<'_> {
                 TypedefItem(Typedef { type_, generics: Generics::default(), item_type }, true)
             }
         };
-        let local_did = cx.tcx.hir().local_def_id(self.hir_id);
         Item {
             name: Some(self.ident.name.clean(cx)),
             source: self.span.clean(cx),
@@ -2340,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/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c22538f21f6..168967cdeb7 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -388,7 +388,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V
             Bool => tcx.lang_items().bool_impl(),
             Str => tcx.lang_items().str_impl(),
             Slice => tcx.lang_items().slice_impl(),
-            Array => tcx.lang_items().slice_impl(),
+            Array => tcx.lang_items().array_impl(),
             Tuple => None,
             Unit => None,
             RawPointer => tcx.lang_items().const_ptr_impl(),
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/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 3000afde0c2..a40b45f9a7e 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -55,6 +55,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
         lang_items.bool_impl(),
         lang_items.char_impl(),
         lang_items.str_impl(),
+        lang_items.array_impl(),
         lang_items.slice_impl(),
         lang_items.slice_u8_impl(),
         lang_items.str_alloc_impl(),
diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp
index 93704638f83..9ce614fda57 100644
--- a/src/rustllvm/ArchiveWrapper.cpp
+++ b/src/rustllvm/ArchiveWrapper.cpp
@@ -35,7 +35,6 @@ struct RustArchiveIterator {
 };
 
 enum class LLVMRustArchiveKind {
-  Other,
   GNU,
   BSD,
   DARWIN,
diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/src/rustllvm/CoverageMappingWrapper.cpp
index 7c8481540aa..4d15e31df15 100644
--- a/src/rustllvm/CoverageMappingWrapper.cpp
+++ b/src/rustllvm/CoverageMappingWrapper.cpp
@@ -38,6 +38,11 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
   CoverageMappingWriter.write(OS);
 }
 
+extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName) {
+  StringRef FuncNameRef(FuncName);
+  return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
+}
+
 extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) {
   StringRef NameRef(Name);
   return IndexedInstrProf::ComputeHash(NameRef);
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 41b14714842..76fe5e7f769 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -311,7 +311,6 @@ static Optional<CodeModel::Model> fromRust(LLVMRustCodeModel Model) {
 }
 
 enum class LLVMRustCodeGenOptLevel {
-  Other,
   None,
   Less,
   Default,
@@ -597,7 +596,6 @@ extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) {
 }
 
 enum class LLVMRustFileType {
-  Other,
   AssemblyFile,
   ObjectFile,
 };
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 667bf4a2ded..9d90b0dfe07 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -366,7 +366,6 @@ LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target,
 }
 
 enum class LLVMRustSynchronizationScope {
-  Other,
   SingleThread,
   CrossThread,
 };
@@ -389,7 +388,6 @@ LLVMRustBuildAtomicFence(LLVMBuilderRef B, LLVMAtomicOrdering Order,
 }
 
 enum class LLVMRustAsmDialect {
-  Other,
   Att,
   Intel,
 };
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/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs
index 758c6c4da92..493c1b9f0ba 100644
--- a/src/test/codegen/naked-functions.rs
+++ b/src/test/codegen/naked-functions.rs
@@ -18,7 +18,7 @@ pub fn naked_empty() {
 // CHECK-NEXT: define void @naked_with_args(i{{[0-9]+( %0)?}})
 pub fn naked_with_args(a: isize) {
     // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: %_1 = alloca i{{[0-9]+}}
+    // CHECK-NEXT: %a = alloca i{{[0-9]+}}
     &a; // keep variable in an alloca
     // CHECK: ret void
 }
@@ -39,7 +39,7 @@ pub fn naked_with_return() -> isize {
 #[naked]
 pub fn naked_with_args_and_return(a: isize) -> isize {
     // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: %_1 = alloca i{{[0-9]+}}
+    // CHECK-NEXT: %a = alloca i{{[0-9]+}}
     &a; // keep variable in an alloca
     // CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
     a
diff --git a/src/test/debuginfo/function-arguments-naked.rs b/src/test/debuginfo/function-arguments-naked.rs
deleted file mode 100644
index 5f3a1eb44e4..00000000000
--- a/src/test/debuginfo/function-arguments-naked.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-// min-lldb-version: 310
-
-// We have to ignore android because of this issue:
-// https://github.com/rust-lang/rust/issues/74847
-// ignore-android
-//
-// We need to use inline assembly, so just use one platform
-// only-x86_64
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:run
-
-// gdb-command:info args
-// gdb-check:No arguments.
-// gdb-command:continue
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:frame variable
-// lldbg-check:(unsigned long) = 111 (unsigned long) = 222
-// lldbr-check:(unsigned long) = 111 (unsigned long) = 222
-// lldb-command:continue
-
-
-#![feature(asm)]
-#![feature(naked_functions)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-fn main() {
-    naked(111, 222);
-}
-
-#[naked]
-extern "C" fn naked(x: usize, y: usize) {
-    unsafe { asm!("ret"); } // #break
-}
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/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit
new file mode 100644
index 00000000000..df94c897e92
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit
@@ -0,0 +1,66 @@
+- // MIR for `foo` before MatchBranchSimplification
++ // MIR for `foo` after MatchBranchSimplification
+  
+  fn foo(_1: std::option::Option<()>) -> () {
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
++         _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x00000000))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+      }
+  
+      bb1: {
+          _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb2: {
+          _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb3: {
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb4: {
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb5: {
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit
new file mode 100644
index 00000000000..06849b4a5d9
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit
@@ -0,0 +1,66 @@
+- // MIR for `foo` before MatchBranchSimplification
++ // MIR for `foo` after MatchBranchSimplification
+  
+  fn foo(_1: std::option::Option<()>) -> () {
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
++         _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x0000000000000000))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+      }
+  
+      bb1: {
+          _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb2: {
+          _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb3: {
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb4: {
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb5: {
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs
new file mode 100644
index 00000000000..91b6bfc836b
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.rs
@@ -0,0 +1,13 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
+
+fn foo(bar: Option<()>) {
+    if matches!(bar, None) {
+      ()
+    }
+}
+
+fn main() {
+  let _ = foo(None);
+  let _ = foo(Some(()));
+}
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/run-make-fulldeps/instrument-coverage/Makefile b/src/test/run-make-fulldeps/instrument-coverage/Makefile
index df47305b547..4392cfec080 100644
--- a/src/test/run-make-fulldeps/instrument-coverage/Makefile
+++ b/src/test/run-make-fulldeps/instrument-coverage/Makefile
@@ -3,55 +3,101 @@
 
 # FIXME(richkadel): Debug the following problem, and reenable on Windows (by
 # removing the `# ignore-msvc` directive above). The current implementation
-# generates a segfault when running the instrumented `main` executable,
-# after the `main` program code executes, but before the process terminates.
-# This most likely points to a problem generating the LLVM "main.profraw"
+# generates a segfault when running the instrumented `testprog` executable,
+# after the `main()` function completes, but before the process terminates.
+# This most likely points to a problem generating the LLVM "testprog.profraw"
 # file.
 
 -include ../tools.mk
 
+UNAME = $(shell uname)
+
+ifeq ($(UNAME),Darwin)
+	INSTR_PROF_DATA_SUFFIX=,regular,live_support
+	DATA_SECTION_PREFIX=__DATA,
+	LLVM_COV_SECTION_PREFIX=__LLVM_COV,
+else
+	INSTR_PROF_DATA_SUFFIX=
+	DATA_SECTION_PREFIX=
+	LLVM_COV_SECTION_PREFIX=
+endif
+
 # This test makes sure that LLVM coverage maps are genereated in LLVM IR.
 
 COMMON_FLAGS=-Zinstrument-coverage
 
 all:
 	# Compile the test program with instrumentation, and also generate LLVM IR
-	$(RUSTC) $(COMMON_FLAGS) main.rs
+	$(RUSTC) $(COMMON_FLAGS) testprog.rs \
+			--emit=link,llvm-ir
+
+	# check the LLVM IR
+ifdef IS_WIN32
+	cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \
+			-check-prefixes=CHECK,WIN32 \
+			-DPRIVATE_GLOBAL="internal global" \
+			-DINSTR_PROF_DATA=".lprfd$$M" \
+			-DINSTR_PROF_NAME=".lprfn$$M" \
+			-DINSTR_PROF_CNTS=".lprfc$$M" \
+			-DINSTR_PROF_VALS=".lprfv$$M" \
+			-DINSTR_PROF_VNODES=".lprfnd$$M" \
+			-DINSTR_PROF_COVMAP=".lcovmap$$M" \
+			-DINSTR_PROF_ORDERFILE=".lorderfile$$M"
+else
+	cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \
+			-check-prefixes=CHECK \
+			-DPRIVATE_GLOBAL="private global" \
+			-DINSTR_PROF_DATA="$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)" \
+			-DINSTR_PROF_NAME="$(DATA_SECTION_PREFIX)__llvm_prf_names" \
+			-DINSTR_PROF_CNTS="$(DATA_SECTION_PREFIX)__llvm_prf_cnts" \
+			-DINSTR_PROF_VALS="$(DATA_SECTION_PREFIX)__llvm_prf_vals" \
+			-DINSTR_PROF_VNODES="$(DATA_SECTION_PREFIX)__llvm_prf_vnds" \
+			-DINSTR_PROF_COVMAP="$(LLVM_COV_SECTION_PREFIX)__llvm_covmap" \
+			-DINSTR_PROF_ORDERFILE="$(DATA_SECTION_PREFIX)__llvm_orderfile"
+endif
 
 	# Run it in order to generate some profiling data,
 	# with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
 	# output the coverage stats for this run.
-	LLVM_PROFILE_FILE="$(TMPDIR)"/main.profraw \
-	  $(call RUN,main)
+	LLVM_PROFILE_FILE="$(TMPDIR)"/testprog.profraw \
+			$(call RUN,testprog)
 
 	# Postprocess the profiling data so it can be used by the llvm-cov tool
 	"$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
-	  "$(TMPDIR)"/main.profraw \
-		-o "$(TMPDIR)"/main.profdata
+			"$(TMPDIR)"/testprog.profraw \
+			-o "$(TMPDIR)"/testprog.profdata
 
 	# Generate a coverage report using `llvm-cov show`. The output ordering
 	# can be non-deterministic, so ignore the return status. If the test fails
 	# when comparing the JSON `export`, the `show` output may be useful when
 	# debugging.
 	"$(LLVM_BIN_DIR)"/llvm-cov show \
-	  --Xdemangler="$(RUST_DEMANGLER)" \
-	  --show-line-counts-or-regions \
-	  --instr-profile="$(TMPDIR)"/main.profdata \
-		$(call BIN,"$(TMPDIR)"/main) \
+			--Xdemangler="$(RUST_DEMANGLER)" \
+			--show-line-counts-or-regions \
+			--instr-profile="$(TMPDIR)"/testprog.profdata \
+			$(call BIN,"$(TMPDIR)"/testprog) \
 		> "$(TMPDIR)"/actual_show_coverage.txt
 
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/actual_show_coverage.txt typical_show_coverage.txt
+else
 	# Compare the show coverage output
 	$(DIFF) typical_show_coverage.txt "$(TMPDIR)"/actual_show_coverage.txt || \
-	  >&2 echo 'diff failed for `llvm-cov show` (might not be an error)'
+		>&2 echo 'diff failed for `llvm-cov show` (might not be an error)'
+endif
 
 	# Generate a coverage report in JSON, using `llvm-cov export`, and fail if
 	# there are differences from the expected output.
 	"$(LLVM_BIN_DIR)"/llvm-cov export \
-	  --summary-only \
-	  --instr-profile="$(TMPDIR)"/main.profdata \
-		$(call BIN,"$(TMPDIR)"/main) \
+			--summary-only \
+			--instr-profile="$(TMPDIR)"/testprog.profdata \
+			$(call BIN,"$(TMPDIR)"/testprog) \
 		| "$(PYTHON)" prettify_json.py \
 		> "$(TMPDIR)"/actual_export_coverage.json
 
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/actual_export_coverage.json expected_export_coverage.json
+else
 	# Check that the exported JSON coverage data matches what we expect
 	$(DIFF) expected_export_coverage.json "$(TMPDIR)"/actual_export_coverage.json
+endif
diff --git a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json
index 9d739a89114..5881cf4b7db 100644
--- a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json
+++ b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json
@@ -3,7 +3,7 @@
     {
       "files": [
         {
-          "filename": "main.rs",
+          "filename": "testprog.rs",
           "summary": {
             "functions": {
               "count": 7,
diff --git a/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt b/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt
new file mode 100644
index 00000000000..5a7cc9a1882
--- /dev/null
+++ b/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt
@@ -0,0 +1,51 @@
+# Check for metadata, variables, declarations, and function definitions injected
+# into LLVM IR when compiling with -Zinstrument-coverage.
+
+WIN32:      $__llvm_profile_runtime_user = comdat any
+
+CHECK:      @__llvm_coverage_mapping = internal constant
+CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8
+
+WIN32:      @__llvm_profile_runtime = external global i32
+
+CHECK:      @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]]
+CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8
+
+CHECK:      @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]]
+CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
+CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called to i8*),
+CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8
+
+CHECK:      @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]]
+CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8
+
+CHECK:      @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]]
+CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main,
+CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog4main to i8*),
+CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8
+
+CHECK:      @__llvm_prf_nm = private constant
+CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1
+
+CHECK:      @llvm.used = appending global
+CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*)
+WIN32-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*)
+CHECK-SAME: i8* bitcast ({ {{.*}} }* @__profd__R{{[a-zA-Z0-9_]*}}testprog4main to i8*)
+CHECK-SAME: i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0)
+CHECK-SAME: section "llvm.metadata"
+
+CHECK:      define hidden { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} {
+CHECK-NEXT: start:
+CHECK-NOT:  bb{{[0-9]+}}:
+CHECK:      %pgocount = load i64, i64* getelementptr inbounds
+CHECK-SAME: * @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
+
+CHECK:      declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]]
+
+WIN32:      define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {
+WIN32-NEXT: %1 = load i32, i32* @__llvm_profile_runtime
+WIN32-NEXT: ret i32 %1
+WIN32-NEXT: }
+
+CHECK:      attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind }
+WIN32:      attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline }
\ No newline at end of file
diff --git a/src/test/run-make-fulldeps/instrument-coverage/main.rs b/src/test/run-make-fulldeps/instrument-coverage/testprog.rs
index 358c25677ae..358c25677ae 100644
--- a/src/test/run-make-fulldeps/instrument-coverage/main.rs
+++ b/src/test/run-make-fulldeps/instrument-coverage/testprog.rs
diff --git a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt b/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt
index 9c593d0809d..ae123afff04 100644
--- a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt
+++ b/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt
@@ -25,14 +25,14 @@
    25|      2|    }
    26|      2|}
   ------------------
-  | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#0}, &str>:
+  | testprog[317d481089b8c8fe]::wrap_with::<testprog[317d481089b8c8fe]::main::{closure#0}, &str>:
   |   22|      1|{
   |   23|      1|    if should_wrap {
   |   24|      1|        wrapper(&inner)
   |   25|      1|    }
   |   26|      1|}
   ------------------
-  | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#1}, &str>:
+  | testprog[317d481089b8c8fe]::wrap_with::<testprog[317d481089b8c8fe]::main::{closure#1}, &str>:
   |   22|      1|{
   |   23|      1|    if should_wrap {
   |   24|      1|        wrapper(&inner)
diff --git a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile
index b11d4c4cab7..e72fe5a5091 100644
--- a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile
+++ b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile
@@ -1,6 +1,5 @@
 # needs-sanitizer-support
 # needs-sanitizer-address
-# only-linux
 
 -include ../tools.mk
 
diff --git a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile
index c2ebd2a6d8c..b9a3f829555 100644
--- a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile
+++ b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile
@@ -1,6 +1,5 @@
 # needs-sanitizer-support
 # needs-sanitizer-address
-# only-linux
 
 -include ../tools.mk
 
diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
index 5ceff16471c..4894f65b114 100644
--- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
+++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
@@ -1,6 +1,5 @@
 # needs-sanitizer-support
 # needs-sanitizer-address
-# only-linux
 
 -include ../tools.mk
 
diff --git a/src/test/run-make-fulldeps/save-analysis/foo.rs b/src/test/run-make-fulldeps/save-analysis/foo.rs
index 789ab686e3f..483eeed0b39 100644
--- a/src/test/run-make-fulldeps/save-analysis/foo.rs
+++ b/src/test/run-make-fulldeps/save-analysis/foo.rs
@@ -1,4 +1,4 @@
-#![ crate_name = "test" ]
+#![crate_name = "test"]
 #![feature(box_syntax)]
 #![feature(rustc_private)]
 #![feature(associated_type_defaults)]
@@ -11,11 +11,10 @@ extern crate krate2;
 extern crate krate2 as krate3;
 
 use rustc_graphviz::RenderOption;
-use std::collections::{HashMap,HashSet};
 use std::cell::RefCell;
+use std::collections::{HashMap, HashSet};
 use std::io::Write;
 
-
 use sub::sub2 as msalias;
 use sub::sub2;
 use sub::sub2::nested_struct as sub_struct;
@@ -32,7 +31,7 @@ static bob: Option<rustc_graphviz::RenderOption> = None;
 // buglink test - see issue #1337.
 
 fn test_alias<I: Iterator>(i: Option<<I as Iterator>::Item>) {
-    let s = sub_struct{ field2: 45u32, };
+    let s = sub_struct { field2: 45u32 };
 
     // import tests
     fn foo(x: &Write) {}
@@ -82,7 +81,7 @@ mod sub {
 
         pub enum nested_enum {
             Nest2 = 2,
-            Nest3 = 3
+            Nest3 = 3,
         }
     }
 }
@@ -103,7 +102,9 @@ struct some_fields {
 type SF = some_fields;
 
 trait SuperTrait {
-    fn qux(&self) { panic!(); }
+    fn qux(&self) {
+        panic!();
+    }
 }
 
 trait SomeTrait: SuperTrait {
@@ -131,8 +132,7 @@ impl SomeTrait for some_fields {
     }
 }
 
-impl SuperTrait for some_fields {
-}
+impl SuperTrait for some_fields {}
 
 impl SubTrait for some_fields {}
 
@@ -145,17 +145,14 @@ impl some_fields {
         42
     }
 
-    fn align_to<T>(&mut self) {
-
-    }
+    fn align_to<T>(&mut self) {}
 
     fn test(&mut self) {
         self.align_to::<bool>();
     }
 }
 
-impl SuperTrait for nofields {
-}
+impl SuperTrait for nofields {}
 impl SomeTrait for nofields {
     fn Method(&self, x: u32) -> u32 {
         self.Method(x);
@@ -181,59 +178,70 @@ enum SomeEnum<'a> {
     Ints(isize, isize),
     Floats(f64, f64),
     Strings(&'a str, &'a str, &'a str),
-    MyTypes(MyType, MyType)
+    MyTypes(MyType, MyType),
 }
 
 #[derive(Copy, Clone)]
 enum SomeOtherEnum {
     SomeConst1,
     SomeConst2,
-    SomeConst3
+    SomeConst3,
 }
 
 enum SomeStructEnum {
-    EnumStruct{a:isize, b:isize},
-    EnumStruct2{f1:MyType, f2:MyType},
-    EnumStruct3{f1:MyType, f2:MyType, f3:SomeEnum<'static>}
+    EnumStruct { a: isize, b: isize },
+    EnumStruct2 { f1: MyType, f2: MyType },
+    EnumStruct3 { f1: MyType, f2: MyType, f3: SomeEnum<'static> },
 }
 
 fn matchSomeEnum(val: SomeEnum) {
     match val {
-        SomeEnum::Ints(int1, int2) => { println(&(int1+int2).to_string()); }
-        SomeEnum::Floats(float1, float2) => { println(&(float2*float1).to_string()); }
-        SomeEnum::Strings(.., s3) => { println(s3); }
-        SomeEnum::MyTypes(mt1, mt2) => { println(&(mt1.field1 - mt2.field1).to_string()); }
+        SomeEnum::Ints(int1, int2) => {
+            println(&(int1 + int2).to_string());
+        }
+        SomeEnum::Floats(float1, float2) => {
+            println(&(float2 * float1).to_string());
+        }
+        SomeEnum::Strings(.., s3) => {
+            println(s3);
+        }
+        SomeEnum::MyTypes(mt1, mt2) => {
+            println(&(mt1.field1 - mt2.field1).to_string());
+        }
     }
 }
 
 fn matchSomeStructEnum(se: SomeStructEnum) {
     match se {
-        SomeStructEnum::EnumStruct{a:a, ..} => println(&a.to_string()),
-        SomeStructEnum::EnumStruct2{f1:f1, f2:f_2} => println(&f_2.field1.to_string()),
-        SomeStructEnum::EnumStruct3{f1, ..} => println(&f1.field1.to_string()),
+        SomeStructEnum::EnumStruct { a: a, .. } => println(&a.to_string()),
+        SomeStructEnum::EnumStruct2 { f1: f1, f2: f_2 } => println(&f_2.field1.to_string()),
+        SomeStructEnum::EnumStruct3 { f1, .. } => println(&f1.field1.to_string()),
     }
 }
 
-
 fn matchSomeStructEnum2(se: SomeStructEnum) {
     use SomeStructEnum::*;
     match se {
-        EnumStruct{a: ref aaa, ..} => println(&aaa.to_string()),
-        EnumStruct2{f1, f2: f2} => println(&f1.field1.to_string()),
-        EnumStruct3{f1, f3: SomeEnum::Ints(..), f2} => println(&f1.field1.to_string()),
-        _ => {},
+        EnumStruct { a: ref aaa, .. } => println(&aaa.to_string()),
+        EnumStruct2 { f1, f2: f2 } => println(&f1.field1.to_string()),
+        EnumStruct3 { f1, f3: SomeEnum::Ints(..), f2 } => println(&f1.field1.to_string()),
+        _ => {}
     }
 }
 
 fn matchSomeOtherEnum(val: SomeOtherEnum) {
     use SomeOtherEnum::{SomeConst2, SomeConst3};
     match val {
-        SomeOtherEnum::SomeConst1 => { println("I'm const1."); }
-        SomeConst2 | SomeConst3 => { println("I'm const2 or const3."); }
+        SomeOtherEnum::SomeConst1 => {
+            println("I'm const1.");
+        }
+        SomeConst2 | SomeConst3 => {
+            println("I'm const2 or const3.");
+        }
     }
 }
 
-fn hello<X: SomeTrait>((z, a) : (u32, String), ex: X) {
+fn hello<X: SomeTrait>((z, a): (u32, String), ex: X) {
     SameDir2::hello(43);
 
     println(&yy.to_string());
@@ -248,8 +256,8 @@ fn hello<X: SomeTrait>((z, a) : (u32, String), ex: X) {
     let x = 32.0f32;
     let _ = (x + ((x * x) + 1.0).sqrt()).ln();
 
-    let s: Box<SomeTrait> = box some_fields {field1: 43};
-    let s2: Box<some_fields> =  box some_fields {field1: 43};
+    let s: Box<SomeTrait> = box some_fields { field1: 43 };
+    let s2: Box<some_fields> = box some_fields { field1: 43 };
     let s3 = box nofields;
 
     s.Method(43);
@@ -302,8 +310,9 @@ mod macro_use_test {
     }
 }
 
-fn main() { // foo
-    let s = box some_fields {field1: 43};
+fn main() {
+    // foo
+    let s = box some_fields { field1: 43 };
     hello((43, "a".to_string()), *s);
     sub::sub2::hello();
     sub2::sub3::hello();
@@ -324,26 +333,24 @@ fn main() { // foo
     let vs = variable_str!(32);
 
     let mut candidates: RefCell<HashMap<&'static str, &'static str>> = RefCell::new(HashMap::new());
-    let _ = blah {
-        used_link_args: RefCell::new([]),
-    };
+    let _ = blah { used_link_args: RefCell::new([]) };
     let s1 = nofields;
-    let s2 = SF { field1: 55};
-    let s3: some_fields = some_fields{ field1: 55};
-    let s4: msalias::nested_struct = sub::sub2::nested_struct{ field2: 55};
-    let s4: msalias::nested_struct = sub2::nested_struct{ field2: 55};
+    let s2 = SF { field1: 55 };
+    let s3: some_fields = some_fields { field1: 55 };
+    let s4: msalias::nested_struct = sub::sub2::nested_struct { field2: 55 };
+    let s4: msalias::nested_struct = sub2::nested_struct { field2: 55 };
     println(&s2.field1.to_string());
-    let s5: MyType = box some_fields{ field1: 55};
-    let s = SameDir::SameStruct{name: "Bob".to_string()};
-    let s = SubDir::SubStruct{name:"Bob".to_string()};
+    let s5: MyType = box some_fields { field1: 55 };
+    let s = SameDir::SameStruct { name: "Bob".to_string() };
+    let s = SubDir::SubStruct { name: "Bob".to_string() };
     let s6: SomeEnum = SomeEnum::MyTypes(box s2.clone(), s5);
     let s7: SomeEnum = SomeEnum::Strings("one", "two", "three");
     matchSomeEnum(s6);
     matchSomeEnum(s7);
     let s8: SomeOtherEnum = SomeOtherEnum::SomeConst2;
     matchSomeOtherEnum(s8);
-    let s9: SomeStructEnum = SomeStructEnum::EnumStruct2{ f1: box some_fields{ field1:10 },
-                                                          f2: box s2 };
+    let s9: SomeStructEnum =
+        SomeStructEnum::EnumStruct2 { f1: box some_fields { field1: 10 }, f2: box s2 };
     matchSomeStructEnum(s9);
 
     for x in &vec![1, 2, 3] {
@@ -404,8 +411,7 @@ impl<'a> Pattern<'a> for CharEqPattern {
 
 struct CharSearcher<'a>(<CharEqPattern as Pattern<'a>>::Searcher);
 
-pub trait Error {
-}
+pub trait Error {}
 
 impl Error + 'static {
     pub fn is<T: Error + 'static>(&self) -> bool {
@@ -419,8 +425,7 @@ impl Error + 'static + Send {
     }
 }
 extern crate rustc_serialize;
-#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable,
-         PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
 struct AllDerives(i32);
 
 fn test_format_args() {
@@ -433,9 +438,8 @@ fn test_format_args() {
     print!("x is {}, y is {1}, name is {n}", x, y, n = name);
 }
 
-
 union TestUnion {
-    f1: u32
+    f1: u32,
 }
 
 struct FrameBuffer;
@@ -454,5 +458,5 @@ trait Foo {
     type Bar = FrameBuffer;
 }
 
-#[doc(include="extra-docs.md")]
+#[doc(include = "extra-docs.md")]
 struct StructWithDocs;
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/const-display.rs b/src/test/rustdoc/const-display.rs
index 8e0d230f7d0..c5016c650e5 100644
--- a/src/test/rustdoc/const-display.rs
+++ b/src/test/rustdoc/const-display.rs
@@ -32,3 +32,12 @@ pub const unsafe fn bar2_gated() -> u32 { 42 }
 
 // @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32'
 pub const unsafe fn bar_not_gated() -> u32 { 42 }
+
+pub struct Foo;
+
+impl Foo {
+    // @has 'foo/struct.Foo.html' '//h4[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature="foo", issue = "none")]
+    pub const unsafe fn gated() -> u32 { 42 }
+}
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-fulldeps/derive-no-std-not-supported.rs b/src/test/ui-fulldeps/derive-no-std-not-supported.rs
deleted file mode 100644
index 1299d82d9c4..00000000000
--- a/src/test/ui-fulldeps/derive-no-std-not-supported.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-#![feature(rustc_private)]
-#![no_std]
-
-extern crate rustc_serialize;
-
-#[derive(RustcEncodable)]
-struct Bar {
-    x: u32,
-}
-
-#[derive(RustcDecodable)]
-struct Baz {
-    x: u32,
-}
-
-fn main() {
-    Bar { x: 0 };
-    Baz { x: 0 };
-}
diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
index 2b349ae9556..119fa3d6fa8 100644
--- a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
+++ b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
@@ -1,16 +1,17 @@
 // run-pass
 
 #![allow(unused_imports)]
-
 #![feature(box_syntax)]
 #![feature(rustc_private)]
 
+extern crate rustc_macros;
 extern crate rustc_serialize;
 
-use rustc_serialize::{Encodable, Decodable};
+use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::json;
+use rustc_serialize::{Decodable, Encodable};
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 struct A {
     foo: Box<[bool]>,
 }
diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
index c2aecbdc167..9dedf990f25 100644
--- a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
+++ b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
@@ -3,32 +3,29 @@
 #![allow(unused_imports)]
 // This briefly tests the capability of `Cell` and `RefCell` to implement the
 // `Encodable` and `Decodable` traits via `#[derive(Encodable, Decodable)]`
-
-
 #![feature(rustc_private)]
 
+extern crate rustc_macros;
 extern crate rustc_serialize;
 
-use std::cell::{Cell, RefCell};
-use rustc_serialize::{Encodable, Decodable};
+use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::json;
+use rustc_serialize::{Decodable, Encodable};
+use std::cell::{Cell, RefCell};
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 struct A {
-    baz: isize
+    baz: isize,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Encodable, Decodable)]
 struct B {
     foo: Cell<bool>,
     bar: RefCell<A>,
 }
 
 fn main() {
-    let obj = B {
-        foo: Cell::new(true),
-        bar: RefCell::new( A { baz: 2 } )
-    };
+    let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
     let s = json::encode(&obj).unwrap();
     let obj2: B = json::decode(&s).unwrap();
     assert_eq!(obj.foo.get(), obj2.foo.get());
diff --git a/src/test/ui-fulldeps/deriving-global.rs b/src/test/ui-fulldeps/deriving-global.rs
index 5ba34a7af6b..921767af981 100644
--- a/src/test/ui-fulldeps/deriving-global.rs
+++ b/src/test/ui-fulldeps/deriving-global.rs
@@ -2,33 +2,29 @@
 
 #![feature(rustc_private)]
 
+extern crate rustc_macros;
 extern crate rustc_serialize;
 
 mod submod {
+    use rustc_macros::{Decodable, Encodable};
+
     // if any of these are implemented without global calls for any
     // function calls, then being in a submodule will (correctly)
     // cause errors about unrecognised module `std` (or `extra`)
-    #[derive(PartialEq, PartialOrd, Eq, Ord,
-               Hash,
-               Clone,
-               Debug,
-               RustcEncodable, RustcDecodable)]
-    enum A { A1(usize), A2(isize) }
+    #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
+    enum A {
+        A1(usize),
+        A2(isize),
+    }
 
-    #[derive(PartialEq, PartialOrd, Eq, Ord,
-               Hash,
-               Clone,
-               Debug,
-               RustcEncodable, RustcDecodable)]
-    struct B { x: usize, y: isize }
+    #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
+    struct B {
+        x: usize,
+        y: isize,
+    }
 
-    #[derive(PartialEq, PartialOrd, Eq, Ord,
-               Hash,
-               Clone,
-               Debug,
-               RustcEncodable, RustcDecodable)]
+    #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
     struct C(usize, isize);
-
 }
 
 pub fn main() {}
diff --git a/src/test/ui-fulldeps/deriving-hygiene.rs b/src/test/ui-fulldeps/deriving-hygiene.rs
index 85ef217e767..8486b8b6e48 100644
--- a/src/test/ui-fulldeps/deriving-hygiene.rs
+++ b/src/test/ui-fulldeps/deriving-hygiene.rs
@@ -2,8 +2,11 @@
 
 #![allow(non_upper_case_globals)]
 #![feature(rustc_private)]
+extern crate rustc_macros;
 extern crate rustc_serialize;
 
+use rustc_macros::{Decodable, Encodable};
+
 pub const other: u8 = 1;
 pub const f: u8 = 1;
 pub const d: u8 = 1;
@@ -11,8 +14,7 @@ pub const s: u8 = 1;
 pub const state: u8 = 1;
 pub const cmp: u8 = 1;
 
-#[derive(Ord,Eq,PartialOrd,PartialEq,Debug,RustcDecodable,RustcEncodable,Hash)]
+#[derive(Ord, Eq, PartialOrd, PartialEq, Debug, Decodable, Encodable, Hash)]
 struct Foo {}
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui-fulldeps/empty-struct-braces-derive.rs b/src/test/ui-fulldeps/empty-struct-braces-derive.rs
index fc85765eea4..6e5eb54629c 100644
--- a/src/test/ui-fulldeps/empty-struct-braces-derive.rs
+++ b/src/test/ui-fulldeps/empty-struct-braces-derive.rs
@@ -3,18 +3,18 @@
 
 #![feature(rustc_private)]
 
+extern crate rustc_macros;
 extern crate rustc_serialize;
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
-         Default, Debug, RustcEncodable, RustcDecodable)]
+use rustc_macros::{Decodable, Encodable};
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
 struct S {}
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
-         Default, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
 struct Z();
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
-         Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
 enum E {
     V {},
     U,
diff --git a/src/test/ui-fulldeps/issue-11881.rs b/src/test/ui-fulldeps/issue-11881.rs
index 7b0abba4d16..6d64aeeda7e 100644
--- a/src/test/ui-fulldeps/issue-11881.rs
+++ b/src/test/ui-fulldeps/issue-11881.rs
@@ -3,26 +3,27 @@
 #![allow(unused_must_use)]
 #![allow(dead_code)]
 #![allow(unused_imports)]
-
 #![feature(rustc_private)]
 
+extern crate rustc_macros;
 extern crate rustc_serialize;
 
-use std::io::Cursor;
-use std::io::prelude::*;
 use std::fmt;
+use std::io::prelude::*;
+use std::io::Cursor;
 use std::slice;
 
-use rustc_serialize::{Encodable, Encoder};
+use rustc_macros::Encodable;
 use rustc_serialize::json;
 use rustc_serialize::opaque;
+use rustc_serialize::{Encodable, Encoder};
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct Foo {
     baz: bool,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Encodable)]
 struct Bar {
     froboz: usize,
 }
@@ -33,19 +34,19 @@ enum WireProtocol {
     // ...
 }
 
-fn encode_json<T: Encodable>(val: &T, wr: &mut Cursor<Vec<u8>>) {
+fn encode_json<T: for<'a> Encodable<json::Encoder<'a>>>(val: &T, wr: &mut Cursor<Vec<u8>>) {
     write!(wr, "{}", json::as_json(val));
 }
-fn encode_opaque<T: Encodable>(val: &T, wr: Vec<u8>) {
+fn encode_opaque<T: Encodable<opaque::Encoder>>(val: &T, wr: Vec<u8>) {
     let mut encoder = opaque::Encoder::new(wr);
     val.encode(&mut encoder);
 }
 
 pub fn main() {
-    let target = Foo{baz: false,};
+    let target = Foo { baz: false };
     let proto = WireProtocol::JSON;
     match proto {
         WireProtocol::JSON => encode_json(&target, &mut Cursor::new(Vec::new())),
-        WireProtocol::Opaque => encode_opaque(&target, Vec::new())
+        WireProtocol::Opaque => encode_opaque(&target, Vec::new()),
     }
 }
diff --git a/src/test/ui-fulldeps/issue-14021.rs b/src/test/ui-fulldeps/issue-14021.rs
index 1898b12c703..be88a593962 100644
--- a/src/test/ui-fulldeps/issue-14021.rs
+++ b/src/test/ui-fulldeps/issue-14021.rs
@@ -4,12 +4,14 @@
 #![allow(unused_imports)]
 #![feature(rustc_private)]
 
+extern crate rustc_macros;
 extern crate rustc_serialize;
 
-use rustc_serialize::{Encodable, Decodable};
+use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::json;
+use rustc_serialize::{Decodable, Encodable};
 
-#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
+#[derive(Encodable, Decodable, PartialEq, Debug)]
 struct UnitLikeStruct;
 
 pub fn main() {
diff --git a/src/test/ui-fulldeps/issue-15924.rs b/src/test/ui-fulldeps/issue-15924.rs
index e3d4b0eb446..5adc2c482f5 100644
--- a/src/test/ui-fulldeps/issue-15924.rs
+++ b/src/test/ui-fulldeps/issue-15924.rs
@@ -3,20 +3,19 @@
 #![allow(unused_imports)]
 #![allow(unused_must_use)]
 // pretty-expanded FIXME #23616
-
 #![feature(rustc_private)]
 
 extern crate rustc_serialize;
 
-use std::fmt;
-use rustc_serialize::{Encoder, Encodable};
 use rustc_serialize::json;
+use rustc_serialize::{Encodable, Encoder};
+use std::fmt;
 
-struct Foo<T: Encodable> {
+struct Foo<T: for<'a> Encodable<json::Encoder<'a>>> {
     v: T,
 }
 
-impl<T: Encodable> Drop for Foo<T> {
+impl<T: for<'a> Encodable<json::Encoder<'a>>> Drop for Foo<T> {
     fn drop(&mut self) {
         json::encode(&self.v);
     }
diff --git a/src/test/ui-fulldeps/issue-24972.rs b/src/test/ui-fulldeps/issue-24972.rs
index 51e134fbf88..044a0c5000e 100644
--- a/src/test/ui-fulldeps/issue-24972.rs
+++ b/src/test/ui-fulldeps/issue-24972.rs
@@ -5,11 +5,18 @@
 
 extern crate rustc_serialize;
 
-use rustc_serialize::{Encodable, Decodable};
+use rustc_serialize::{json, Decodable, Encodable};
 use std::fmt::Display;
 
-pub trait Entity : Decodable + Encodable + Sized {
-    type Key: Clone + Decodable + Encodable + ToString + Display + Eq + Ord + Sized;
+pub trait Entity: Decodable<json::Decoder> + for<'a> Encodable<json::Encoder<'a>> + Sized {
+    type Key: Clone
+        + Decodable<json::Decoder>
+        + for<'a> Encodable<json::Encoder<'a>>
+        + ToString
+        + Display
+        + Eq
+        + Ord
+        + Sized;
 
     fn id(&self) -> Self::Key;
 
@@ -20,7 +27,10 @@ pub struct DbRef<E: Entity> {
     pub id: E::Key,
 }
 
-impl<E> DbRef<E> where E: Entity {
+impl<E> DbRef<E>
+where
+    E: Entity,
+{
     fn get(self) -> Option<E> {
         E::find_by_id(self.id)
     }
diff --git a/src/test/ui-fulldeps/issue-4016.rs b/src/test/ui-fulldeps/issue-4016.rs
index 96157c2f426..4fd192497a0 100644
--- a/src/test/ui-fulldeps/issue-4016.rs
+++ b/src/test/ui-fulldeps/issue-4016.rs
@@ -1,14 +1,13 @@
 // run-pass
 
 #![allow(dead_code)]
-
 #![feature(rustc_private)]
 
 extern crate rustc_serialize;
 
 use rustc_serialize::{json, Decodable};
 
-trait JD : Decodable {}
+trait JD: Decodable<json::Decoder> {}
 
 fn exec<T: JD>() {
     let doc = json::from_str("").unwrap();
diff --git a/src/test/ui-fulldeps/rustc_encodable_hygiene.rs b/src/test/ui-fulldeps/rustc_encodable_hygiene.rs
index b49135cb60b..452110a65e4 100644
--- a/src/test/ui-fulldeps/rustc_encodable_hygiene.rs
+++ b/src/test/ui-fulldeps/rustc_encodable_hygiene.rs
@@ -2,11 +2,13 @@
 
 #![feature(rustc_private)]
 
+extern crate rustc_macros;
 #[allow(dead_code)]
-
 extern crate rustc_serialize;
 
-#[derive(RustcDecodable, RustcEncodable,Debug)]
+use rustc_macros::{Decodable, Encodable};
+
+#[derive(Decodable, Encodable, Debug)]
 struct A {
     a: String,
 }
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/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
index c7b0fbeb0e3..d0942f78bb8 100644
--- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout
+++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
index 59ed68c2a77..dc06fd74a4b 100644
--- a/src/test/ui/ast-json/ast-json-output.stdout
+++ b/src/test/ui/ast-json/ast-json-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/const-generics/apit-with-const-param.rs b/src/test/ui/const-generics/apit-with-const-param.rs
index f9c6e201b17..facc0bcf513 100644
--- a/src/test/ui/const-generics/apit-with-const-param.rs
+++ b/src/test/ui/const-generics/apit-with-const-param.rs
@@ -1,7 +1,9 @@
 // check-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 trait Trait {}
 
diff --git a/src/test/ui/const-generics/apit-with-const-param.stderr b/src/test/ui/const-generics/apit-with-const-param.stderr
deleted file mode 100644
index 4389e4738ea..00000000000
--- a/src/test/ui/const-generics/apit-with-const-param.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/apit-with-const-param.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/argument_order.rs b/src/test/ui/const-generics/argument_order.rs
index 1d1adf39434..9e071e674e7 100644
--- a/src/test/ui/const-generics/argument_order.rs
+++ b/src/test/ui/const-generics/argument_order.rs
@@ -1,14 +1,13 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![allow(incomplete_features)]
 
-struct Bad<const N: usize, T> { //~ ERROR type parameters must be declared prior
+struct Bad<const N: usize, T> {
     arr: [u8; { N }],
     another: T,
 }
 
 struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
-    //~^ ERROR type parameters must be declared prior
-    //~| ERROR lifetime parameters must be declared prior
+    //~^ ERROR lifetime parameters must be declared prior
     a: &'a T,
     b: &'b U,
 }
diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr
index 19e895b8eb8..d6546a768d2 100644
--- a/src/test/ui/const-generics/argument_order.stderr
+++ b/src/test/ui/const-generics/argument_order.stderr
@@ -1,39 +1,18 @@
-error: type parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:4:28
-   |
-LL | struct Bad<const N: usize, T> {
-   |           -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
-
 error: lifetime parameters must be declared prior to const parameters
   --> $DIR/argument_order.rs:9:32
    |
 LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
-   |               -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
-
-error: type parameters must be declared prior to const parameters
-  --> $DIR/argument_order.rs:9:36
-   |
-LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
-   |               ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
-
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/argument_order.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   |               -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>`
 
 error[E0747]: lifetime provided when a type was expected
-  --> $DIR/argument_order.rs:17:23
+  --> $DIR/argument_order.rs:16:23
    |
 LL |     let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
    |                       ^^^^^^^
    |
    = note: lifetime arguments must be provided before type arguments
-   = help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>`
+   = help: reorder the arguments: lifetimes, then consts: `<'a, 'b, N, T, M, U>`
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.full.stderr
new file mode 100644
index 00000000000..cf4487b5829
--- /dev/null
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.full.stderr
@@ -0,0 +1,18 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/array-size-in-generic-struct-param.rs:9:38
+   |
+LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
+   |                                      ^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/array-size-in-generic-struct-param.rs:20:10
+   |
+LL |     arr: [u8; CFG.arr_size],
+   |          ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
new file mode 100644
index 00000000000..61d23475c6f
--- /dev/null
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
@@ -0,0 +1,27 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/array-size-in-generic-struct-param.rs:9:48
+   |
+LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
+   |                                                ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/array-size-in-generic-struct-param.rs:20:15
+   |
+LL |     arr: [u8; CFG.arr_size],
+   |               ^^^ non-trivial anonymous constants must not depend on the parameter `CFG`
+   |
+   = help: it is currently only allowed to use either `CFG` or `{ CFG }` as generic constants
+
+error: using `Config` as const generic parameters is forbidden
+  --> $DIR/array-size-in-generic-struct-param.rs:18:21
+   |
+LL | struct B<const CFG: Config> {
+   |                     ^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
index 5c02e585dc8..aa1a3b9cf28 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
@@ -1,9 +1,14 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// Tests that array sizes that depend on const-params are checked using `ConstEvaluatable`.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 #[allow(dead_code)]
 struct ArithArrayLen<const N: usize>([u32; 0 + N]);
-//~^ ERROR constant expression depends on a generic parameter
+//[full]~^ ERROR constant expression depends on a generic parameter
+//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
 
 #[derive(PartialEq, Eq)]
 struct Config {
@@ -11,7 +16,10 @@ struct Config {
 }
 
 struct B<const CFG: Config> {
-    arr: [u8; CFG.arr_size], //~ ERROR constant expression depends on a generic parameter
+    //[min]~^ ERROR using `Config` as const generic parameters is forbidden
+    arr: [u8; CFG.arr_size],
+    //[full]~^ ERROR constant expression depends on a generic parameter
+    //[min]~^^ ERROR generic parameters must not be used inside of non trivial
 }
 
 const C: Config = Config { arr_size: 5 };
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr
deleted file mode 100644
index ad67a87265b..00000000000
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/array-size-in-generic-struct-param.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: constant expression depends on a generic parameter
-  --> $DIR/array-size-in-generic-struct-param.rs:5:38
-   |
-LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
-   |                                      ^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: constant expression depends on a generic parameter
-  --> $DIR/array-size-in-generic-struct-param.rs:14:10
-   |
-LL |     arr: [u8; CFG.arr_size],
-   |          ^^^^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/broken-mir-1.rs b/src/test/ui/const-generics/broken-mir-1.rs
index f137be2d6a6..d13ae12c03b 100644
--- a/src/test/ui/const-generics/broken-mir-1.rs
+++ b/src/test/ui/const-generics/broken-mir-1.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait Foo {
     fn foo(&self);
diff --git a/src/test/ui/const-generics/broken-mir-1.stderr b/src/test/ui/const-generics/broken-mir-1.stderr
deleted file mode 100644
index a5532bde1f5..00000000000
--- a/src/test/ui/const-generics/broken-mir-1.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/broken-mir-1.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/broken-mir-2.rs b/src/test/ui/const-generics/broken-mir-2.rs
index 2cd035639ee..2f9afe0b464 100644
--- a/src/test/ui/const-generics/broken-mir-2.rs
+++ b/src/test/ui/const-generics/broken-mir-2.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 use std::fmt::Debug;
 
diff --git a/src/test/ui/const-generics/broken-mir-2.stderr b/src/test/ui/const-generics/broken-mir-2.stderr
deleted file mode 100644
index c36ef845097..00000000000
--- a/src/test/ui/const-generics/broken-mir-2.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/broken-mir-2.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/cannot-infer-const-args.full.stderr
new file mode 100644
index 00000000000..053139787ed
--- /dev/null
+++ b/src/test/ui/const-generics/cannot-infer-const-args.full.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/cannot-infer-const-args.rs:12:5
+   |
+LL |     foo();
+   |     ^^^
+   |
+   = note: unable to infer the value of a const parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/cannot-infer-const-args.min.stderr
new file mode 100644
index 00000000000..053139787ed
--- /dev/null
+++ b/src/test/ui/const-generics/cannot-infer-const-args.min.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/cannot-infer-const-args.rs:12:5
+   |
+LL |     foo();
+   |     ^^^
+   |
+   = note: unable to infer the value of a const parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/cannot-infer-const-args.rs
index 2f6ad2654c1..2d74b4788bf 100644
--- a/src/test/ui/const-generics/cannot-infer-const-args.rs
+++ b/src/test/ui/const-generics/cannot-infer-const-args.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const X: usize>() -> usize {
     0
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr
deleted file mode 100644
index b29d27e5247..00000000000
--- a/src/test/ui/const-generics/cannot-infer-const-args.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/cannot-infer-const-args.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-const-args.rs:9:5
-   |
-LL |     foo();
-   |     ^^^
-   |
-   = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/coerce_unsized_array.rs b/src/test/ui/const-generics/coerce_unsized_array.rs
index b28768a5163..a3c295f73c7 100644
--- a/src/test/ui/const-generics/coerce_unsized_array.rs
+++ b/src/test/ui/const-generics/coerce_unsized_array.rs
@@ -1,6 +1,9 @@
 // run-pass
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const N: usize>(v: &[u8; N]) -> &[u8] {
     v
diff --git a/src/test/ui/const-generics/concrete-const-as-fn-arg.rs b/src/test/ui/const-generics/concrete-const-as-fn-arg.rs
index 18ebba49f6f..7771bf33601 100644
--- a/src/test/ui/const-generics/concrete-const-as-fn-arg.rs
+++ b/src/test/ui/const-generics/concrete-const-as-fn-arg.rs
@@ -1,8 +1,10 @@
 // Test that a concrete const type i.e. A<2>, can be used as an argument type in a function
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize>; // ok
 
diff --git a/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr b/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr
deleted file mode 100644
index c8f3a8beaf8..00000000000
--- a/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/concrete-const-as-fn-arg.rs:4:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/concrete-const-impl-method.rs b/src/test/ui/const-generics/concrete-const-impl-method.rs
index c1ddf9a3314..edb403ce8fd 100644
--- a/src/test/ui/const-generics/concrete-const-impl-method.rs
+++ b/src/test/ui/const-generics/concrete-const-impl-method.rs
@@ -1,9 +1,11 @@
 // Test that a method/associated non-method within an impl block of a concrete const type i.e. A<2>,
 // is callable.
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct A<const N: u32>;
 
diff --git a/src/test/ui/const-generics/concrete-const-impl-method.stderr b/src/test/ui/const-generics/concrete-const-impl-method.stderr
deleted file mode 100644
index 5edb4f4f6cd..00000000000
--- a/src/test/ui/const-generics/concrete-const-impl-method.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/concrete-const-impl-method.rs:5:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/condition-in-trait-const-arg.rs b/src/test/ui/const-generics/condition-in-trait-const-arg.rs
index 9d8aaed54bd..77b68052fc0 100644
--- a/src/test/ui/const-generics/condition-in-trait-const-arg.rs
+++ b/src/test/ui/const-generics/condition-in-trait-const-arg.rs
@@ -1,7 +1,10 @@
+// Checks that `impl Trait<{anon_const}> for Type` evaluates successfully.
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 trait IsZeroTrait<const IS_ZERO: bool>{}
 
diff --git a/src/test/ui/const-generics/condition-in-trait-const-arg.stderr b/src/test/ui/const-generics/condition-in-trait-const-arg.stderr
deleted file mode 100644
index 9ac33454128..00000000000
--- a/src/test/ui/const-generics/condition-in-trait-const-arg.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/condition-in-trait-const-arg.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-arg-in-fn.rs b/src/test/ui/const-generics/const-arg-in-fn.rs
index 5ea2cf92fdc..5c438efd82a 100644
--- a/src/test/ui/const-generics/const-arg-in-fn.rs
+++ b/src/test/ui/const-generics/const-arg-in-fn.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn const_u32_identity<const X: u32>() -> u32 {
     X
diff --git a/src/test/ui/const-generics/const-arg-in-fn.stderr b/src/test/ui/const-generics/const-arg-in-fn.stderr
deleted file mode 100644
index bb66849c7fe..00000000000
--- a/src/test/ui/const-generics/const-arg-in-fn.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-arg-in-fn.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs
index 9f989ee20a5..13ca56ad3e6 100644
--- a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs
+++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![allow(incomplete_features)]
 
 type Array<T, const N: usize> = [T; N];
 
diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
index 4a6241de1b4..2e2bfed51fb 100644
--- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
+++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
@@ -1,21 +1,9 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-arg-type-arg-misordered.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
 error[E0747]: constant provided when a type was expected
   --> $DIR/const-arg-type-arg-misordered.rs:6:35
    |
 LL | fn foo<const N: usize>() -> Array<N, ()> {
    |                                   ^
-   |
-   = note: type arguments must be provided before constant arguments
-   = help: reorder the arguments: types, then consts: `<T, N>`
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/const-generics/const-argument-non-static-lifetime.rs b/src/test/ui/const-generics/const-argument-non-static-lifetime.rs
index bc09ba2ab55..dc34621b905 100644
--- a/src/test/ui/const-generics/const-argument-non-static-lifetime.rs
+++ b/src/test/ui/const-generics/const-argument-non-static-lifetime.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full
+// FIXME(#75323) Omitted min revision for now due to ICE.
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
 #![allow(dead_code)]
 
 fn test<const N: usize>() {}
diff --git a/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr b/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr
deleted file mode 100644
index 53a7550090d..00000000000
--- a/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-argument-non-static-lifetime.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-expression-parameter.full.stderr b/src/test/ui/const-generics/const-expression-parameter.full.stderr
new file mode 100644
index 00000000000..496af9c6e02
--- /dev/null
+++ b/src/test/ui/const-generics/const-expression-parameter.full.stderr
@@ -0,0 +1,8 @@
+error: expected one of `,` or `>`, found `+`
+  --> $DIR/const-expression-parameter.rs:16:22
+   |
+LL |     i32_identity::<1 + 2>();
+   |                      ^ expected one of `,` or `>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const-expression-parameter.min.stderr b/src/test/ui/const-generics/const-expression-parameter.min.stderr
new file mode 100644
index 00000000000..496af9c6e02
--- /dev/null
+++ b/src/test/ui/const-generics/const-expression-parameter.min.stderr
@@ -0,0 +1,8 @@
+error: expected one of `,` or `>`, found `+`
+  --> $DIR/const-expression-parameter.rs:16:22
+   |
+LL |     i32_identity::<1 + 2>();
+   |                      ^ expected one of `,` or `>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs
index e0b66a7c14c..7a1eaf9f939 100644
--- a/src/test/ui/const-generics/const-expression-parameter.rs
+++ b/src/test/ui/const-generics/const-expression-parameter.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn i32_identity<const X: i32>() -> i32 {
     5
diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr
deleted file mode 100644
index e421c22be01..00000000000
--- a/src/test/ui/const-generics/const-expression-parameter.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: expected one of `,` or `>`, found `+`
-  --> $DIR/const-expression-parameter.rs:13:22
-   |
-LL |     i32_identity::<1 + 2>();
-   |                      ^ expected one of `,` or `>`
-
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-expression-parameter.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-fn-with-const-param.rs b/src/test/ui/const-generics/const-fn-with-const-param.rs
index bbc55815e9a..add1290b1d9 100644
--- a/src/test/ui/const-generics/const-fn-with-const-param.rs
+++ b/src/test/ui/const-generics/const-fn-with-const-param.rs
@@ -1,6 +1,10 @@
+// Checks that `const fn` with const params can be used.
 // run-pass
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 const fn const_u32_identity<const X: u32>() -> u32 {
     X
diff --git a/src/test/ui/const-generics/const-fn-with-const-param.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr
deleted file mode 100644
index 109b5002848..00000000000
--- a/src/test/ui/const-generics/const-fn-with-const-param.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-fn-with-const-param.rs:2:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-generic-array-wrapper.rs b/src/test/ui/const-generics/const-generic-array-wrapper.rs
index 3e43387163b..34edd0b4a8e 100644
--- a/src/test/ui/const-generics/const-generic-array-wrapper.rs
+++ b/src/test/ui/const-generics/const-generic-array-wrapper.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<T, const N: usize>([T; N]);
 
diff --git a/src/test/ui/const-generics/const-generic-array-wrapper.stderr b/src/test/ui/const-generics/const-generic-array-wrapper.stderr
deleted file mode 100644
index 47448bbd19d..00000000000
--- a/src/test/ui/const-generics/const-generic-array-wrapper.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-generic-array-wrapper.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-generic-type_name.rs b/src/test/ui/const-generics/const-generic-type_name.rs
index 22f9bd2a0f0..a954c026352 100644
--- a/src/test/ui/const-generics/const-generic-type_name.rs
+++ b/src/test/ui/const-generics/const-generic-type_name.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(Debug)]
 struct S<const N: usize>;
diff --git a/src/test/ui/const-generics/const-generic-type_name.stderr b/src/test/ui/const-generics/const-generic-type_name.stderr
deleted file mode 100644
index f161739c9c8..00000000000
--- a/src/test/ui/const-generics/const-generic-type_name.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-generic-type_name.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-param-after-const-literal-arg.rs b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs
index 19c4120eb2f..3982f7a7f12 100644
--- a/src/test/ui/const-generics/const-param-after-const-literal-arg.rs
+++ b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs
@@ -1,7 +1,9 @@
 // check-pass
+// revisions: full min
 
-#![allow(incomplete_features)]
-#![feature(const_generics)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const A: usize, const B: usize>;
 
diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs
index 756e961ce91..0d787d9a67b 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.rs
+++ b/src/test/ui/const-generics/const-param-before-other-params.rs
@@ -5,8 +5,6 @@ fn bar<const X: (), 'a>(_: &'a ()) {
     //~^ ERROR lifetime parameters must be declared prior to const parameters
 }
 
-fn foo<const X: (), T>(_: &T) {
-    //~^ ERROR type parameters must be declared prior to const parameters
-}
+fn foo<const X: (), T>(_: &T) {}
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr
index 9b18b8c79ed..1194dd30f61 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.stderr
@@ -2,13 +2,7 @@ error: lifetime parameters must be declared prior to const parameters
   --> $DIR/const-param-before-other-params.rs:4:21
    |
 LL | fn bar<const X: (), 'a>(_: &'a ()) {
-   |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
+   |       --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: ()>`
 
-error: type parameters must be declared prior to const parameters
-  --> $DIR/const-param-before-other-params.rs:8:21
-   |
-LL | fn foo<const X: (), T>(_: &T) {
-   |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.stderr b/src/test/ui/const-generics/const-param-elided-lifetime.full.stderr
index 8c50fb73679..aa29d61d917 100644
--- a/src/test/ui/const-generics/const-param-elided-lifetime.stderr
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.full.stderr
@@ -1,42 +1,33 @@
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:9:19
+  --> $DIR/const-param-elided-lifetime.rs:11:19
    |
 LL | struct A<const N: &u8>;
    |                   ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:13:15
+  --> $DIR/const-param-elided-lifetime.rs:16:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:14:21
+  --> $DIR/const-param-elided-lifetime.rs:19:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:18:15
+  --> $DIR/const-param-elided-lifetime.rs:24:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:21:17
+  --> $DIR/const-param-elided-lifetime.rs:28:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
 
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-param-elided-lifetime.rs:6:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0637`.
diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
new file mode 100644
index 00000000000..bdd1da96c75
--- /dev/null
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
@@ -0,0 +1,78 @@
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/const-param-elided-lifetime.rs:11:19
+   |
+LL | struct A<const N: &u8>;
+   |                   ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/const-param-elided-lifetime.rs:16:15
+   |
+LL | impl<const N: &u8> A<N> {
+   |               ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/const-param-elided-lifetime.rs:19:21
+   |
+LL |     fn foo<const M: &u8>(&self) {}
+   |                     ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/const-param-elided-lifetime.rs:24:15
+   |
+LL | impl<const N: &u8> B for A<N> {}
+   |               ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/const-param-elided-lifetime.rs:28:17
+   |
+LL | fn bar<const N: &u8>() {}
+   |                 ^ explicit lifetime name needed here
+
+error: using `&'static u8` as const generic parameters is forbidden
+  --> $DIR/const-param-elided-lifetime.rs:11:19
+   |
+LL | struct A<const N: &u8>;
+   |                   ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static u8` as const generic parameters is forbidden
+  --> $DIR/const-param-elided-lifetime.rs:16:15
+   |
+LL | impl<const N: &u8> A<N> {
+   |               ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static u8` as const generic parameters is forbidden
+  --> $DIR/const-param-elided-lifetime.rs:24:15
+   |
+LL | impl<const N: &u8> B for A<N> {}
+   |               ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static u8` as const generic parameters is forbidden
+  --> $DIR/const-param-elided-lifetime.rs:28:17
+   |
+LL | fn bar<const N: &u8>() {}
+   |                 ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static u8` as const generic parameters is forbidden
+  --> $DIR/const-param-elided-lifetime.rs:19:21
+   |
+LL |     fn foo<const M: &u8>(&self) {}
+   |                     ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0637`.
diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.rs b/src/test/ui/const-generics/const-param-elided-lifetime.rs
index 5e6b6c4dabe..814b71d4b74 100644
--- a/src/test/ui/const-generics/const-param-elided-lifetime.rs
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.rs
@@ -2,23 +2,31 @@
 // behaviour of trait bounds where `fn foo<T: Ord<&u8>>() {}` is illegal. Though we could change
 // elided lifetimes within the type of a const generic parameters to be 'static, like elided
 // lifetimes within const/static items.
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: &u8>;
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
+//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
 trait B {}
 
-impl<const N: &u8> A<N> { //~ ERROR `&` without an explicit lifetime name cannot be used here
+impl<const N: &u8> A<N> {
+//~^ ERROR `&` without an explicit lifetime name cannot be used here
+//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
     fn foo<const M: &u8>(&self) {}
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
+    //[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
 }
 
 impl<const N: &u8> B for A<N> {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
+//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
 
 fn bar<const N: &u8>() {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
+//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.full.stderr b/src/test/ui/const-generics/const-param-from-outer-fn.full.stderr
new file mode 100644
index 00000000000..5a126f5c3c6
--- /dev/null
+++ b/src/test/ui/const-generics/const-param-from-outer-fn.full.stderr
@@ -0,0 +1,13 @@
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/const-param-from-outer-fn.rs:9:9
+   |
+LL | fn foo<const X: u32>() {
+   |              - const parameter from outer function
+LL |     fn bar() -> u32 {
+   |        --- try adding a local generic parameter in this method instead
+LL |         X
+   |         ^ use of generic parameter from outer function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.min.stderr b/src/test/ui/const-generics/const-param-from-outer-fn.min.stderr
new file mode 100644
index 00000000000..5a126f5c3c6
--- /dev/null
+++ b/src/test/ui/const-generics/const-param-from-outer-fn.min.stderr
@@ -0,0 +1,13 @@
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/const-param-from-outer-fn.rs:9:9
+   |
+LL | fn foo<const X: u32>() {
+   |              - const parameter from outer function
+LL |     fn bar() -> u32 {
+   |        --- try adding a local generic parameter in this method instead
+LL |         X
+   |         ^ use of generic parameter from outer function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.rs b/src/test/ui/const-generics/const-param-from-outer-fn.rs
index 4b8e2db7233..e1376c6e108 100644
--- a/src/test/ui/const-generics/const-param-from-outer-fn.rs
+++ b/src/test/ui/const-generics/const-param-from-outer-fn.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const X: u32>() {
     fn bar() -> u32 {
diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/const-param-from-outer-fn.stderr
deleted file mode 100644
index 30bd1d72914..00000000000
--- a/src/test/ui/const-generics/const-param-from-outer-fn.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0401]: can't use generic parameters from outer function
-  --> $DIR/const-param-from-outer-fn.rs:6:9
-   |
-LL | fn foo<const X: u32>() {
-   |              - const parameter from outer function
-LL |     fn bar() -> u32 {
-   |        --- try adding a local generic parameter in this method instead
-LL |         X
-   |         ^ use of generic parameter from outer function
-
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-param-from-outer-fn.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0401`.
diff --git a/src/test/ui/const-generics/const-param-in-trait.rs b/src/test/ui/const-generics/const-param-in-trait.rs
index 68740725711..9d31162c1c6 100644
--- a/src/test/ui/const-generics/const-param-in-trait.rs
+++ b/src/test/ui/const-generics/const-param-in-trait.rs
@@ -1,8 +1,12 @@
+// Check that const parameters are permitted in traits.
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
-trait Trait<const T: ()> {}
+
+trait Trait<const T: u8> {}
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-in-trait.stderr b/src/test/ui/const-generics/const-param-in-trait.stderr
deleted file mode 100644
index a2e367b25ad..00000000000
--- a/src/test/ui/const-generics/const-param-in-trait.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-param-in-trait.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.full.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.full.stderr
new file mode 100644
index 00000000000..f7ad579dbca
--- /dev/null
+++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.full.stderr
@@ -0,0 +1,15 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-const-param.rs:12:52
+   |
+LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
+   |                                                    ^ the type must not depend on the parameter `N`
+
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-const-param.rs:16:40
+   |
+LL | pub struct SelfDependent<const N: [u8; N]>;
+   |                                        ^ the type must not depend on the parameter `N`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0770`.
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
new file mode 100644
index 00000000000..103f4c36fae
--- /dev/null
+++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
@@ -0,0 +1,33 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-const-param.rs:12:52
+   |
+LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
+   |                                                    ^ the type must not depend on the parameter `N`
+
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-const-param.rs:16:40
+   |
+LL | pub struct SelfDependent<const N: [u8; N]>;
+   |                                        ^ the type must not depend on the parameter `N`
+
+error: using `[u8; _]` as const generic parameters is forbidden
+  --> $DIR/const-param-type-depends-on-const-param.rs:12:47
+   |
+LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
+   |                                               ^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `[u8; _]` as const generic parameters is forbidden
+  --> $DIR/const-param-type-depends-on-const-param.rs:16:35
+   |
+LL | pub struct SelfDependent<const N: [u8; N]>;
+   |                                   ^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0770`.
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
index 5aa3617d1d7..d21a7cec117 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
+++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 // Currently, const parameters cannot depend on other generic parameters,
 // as our current implementation can't really support this.
@@ -8,8 +11,10 @@
 
 pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
+//[min]~^^ ERROR using `[u8; _]` as const generic parameters is forbidden
 
 pub struct SelfDependent<const N: [u8; N]>;
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
+//[min]~^^ ERROR using `[u8; _]` as const generic parameters is forbidden
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr
deleted file mode 100644
index f6606aea726..00000000000
--- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-const-param.rs:9:52
-   |
-LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
-   |                                                    ^ the type must not depend on the parameter `N`
-
-error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-const-param.rs:12:40
-   |
-LL | pub struct SelfDependent<const N: [u8; N]>;
-   |                                        ^ the type must not depend on the parameter `N`
-
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-param-type-depends-on-const-param.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0770`.
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr
index d081dcbbc7a..ba99c87722c 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr
@@ -1,27 +1,18 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-type-param.rs:9:34
+  --> $DIR/const-param-type-depends-on-type-param.rs:12:34
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
    |                                  ^ the type must not depend on the parameter `T`
 
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-param-type-depends-on-type-param.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
 error[E0392]: parameter `T` is never used
-  --> $DIR/const-param-type-depends-on-type-param.rs:9:22
+  --> $DIR/const-param-type-depends-on-type-param.rs:12:22
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
    |                      ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0392, E0770.
 For more information about an error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr
new file mode 100644
index 00000000000..ba99c87722c
--- /dev/null
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr
@@ -0,0 +1,18 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-type-param.rs:12:34
+   |
+LL | pub struct Dependent<T, const X: T>([(); X]);
+   |                                  ^ the type must not depend on the parameter `T`
+
+error[E0392]: parameter `T` is never used
+  --> $DIR/const-param-type-depends-on-type-param.rs:12:22
+   |
+LL | pub struct Dependent<T, const X: T>([(); X]);
+   |                      ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0392, E0770.
+For more information about an error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
index 7fe04a43412..93ae1117512 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 // Currently, const parameters cannot depend on other generic parameters,
 // as our current implementation can't really support this.
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.full.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.full.stderr
new file mode 100644
index 00000000000..0f4f007f9d2
--- /dev/null
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.full.stderr
@@ -0,0 +1,14 @@
+error: const parameter `x` should have an upper case name
+  --> $DIR/const-parameter-uppercase-lint.rs:9:15
+   |
+LL | fn noop<const x: u32>() {
+   |               ^ help: convert the identifier to upper case (notice the capitalization): `X`
+   |
+note: the lint level is defined here
+  --> $DIR/const-parameter-uppercase-lint.rs:7:9
+   |
+LL | #![deny(non_upper_case_globals)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.min.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.min.stderr
new file mode 100644
index 00000000000..0f4f007f9d2
--- /dev/null
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.min.stderr
@@ -0,0 +1,14 @@
+error: const parameter `x` should have an upper case name
+  --> $DIR/const-parameter-uppercase-lint.rs:9:15
+   |
+LL | fn noop<const x: u32>() {
+   |               ^ help: convert the identifier to upper case (notice the capitalization): `X`
+   |
+note: the lint level is defined here
+  --> $DIR/const-parameter-uppercase-lint.rs:7:9
+   |
+LL | #![deny(non_upper_case_globals)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
index 54a33e21812..b9bd6666af3 100644
--- a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 #![deny(non_upper_case_globals)]
 
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
deleted file mode 100644
index b7febed7bdd..00000000000
--- a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-parameter-uppercase-lint.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: const parameter `x` should have an upper case name
-  --> $DIR/const-parameter-uppercase-lint.rs:6:15
-   |
-LL | fn noop<const x: u32>() {
-   |               ^ help: convert the identifier to upper case (notice the capitalization): `X`
-   |
-note: the lint level is defined here
-  --> $DIR/const-parameter-uppercase-lint.rs:4:9
-   |
-LL | #![deny(non_upper_case_globals)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/const-types.rs b/src/test/ui/const-generics/const-types.rs
index bde80f4a1ed..cd34cfc0478 100644
--- a/src/test/ui/const-generics/const-types.rs
+++ b/src/test/ui/const-generics/const-types.rs
@@ -1,7 +1,10 @@
+// Check that arrays can be used with generic const and type.
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 #![allow(dead_code, unused_variables)]
 
diff --git a/src/test/ui/const-generics/const-types.stderr b/src/test/ui/const-generics/const-types.stderr
deleted file mode 100644
index 4628c900318..00000000000
--- a/src/test/ui/const-generics/const-types.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-types.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs
new file mode 100644
index 00000000000..72967640a8e
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs
@@ -0,0 +1,20 @@
+// run-pass
+// Checks a complicated usage of unordered params
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
+  args: &'a [&'a [T; M]; N],
+  specifier: A,
+}
+
+fn main() {
+  let array = [1, 2, 3];
+  let nest = [&array];
+  let _ = NestedArrays {
+    args: &nest,
+    specifier: true,
+  };
+}
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
new file mode 100644
index 00000000000..ea3a8c14b98
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
@@ -0,0 +1,12 @@
+// Checks that lifetimes cannot be interspersed between consts and types.
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
+//~^ Error lifetime parameters must be declared prior to const parameters
+
+struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
+//~^ Error lifetime parameters must be declared prior to type parameters
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
new file mode 100644
index 00000000000..0f6d7f1065a
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
@@ -0,0 +1,14 @@
+error: lifetime parameters must be declared prior to const parameters
+  --> $DIR/intermixed-lifetime.rs:6:28
+   |
+LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
+   |           -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
+
+error: lifetime parameters must be declared prior to type parameters
+  --> $DIR/intermixed-lifetime.rs:9:37
+   |
+LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
+   |           --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/defaults/needs-feature.min.stderr b/src/test/ui/const-generics/defaults/needs-feature.min.stderr
new file mode 100644
index 00000000000..7058327fdce
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/needs-feature.min.stderr
@@ -0,0 +1,8 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/needs-feature.rs:10:26
+   |
+LL | struct A<const N: usize, T=u32>(T);
+   |         -----------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/defaults/needs-feature.none.stderr b/src/test/ui/const-generics/defaults/needs-feature.none.stderr
new file mode 100644
index 00000000000..3b6f63a8efe
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/needs-feature.none.stderr
@@ -0,0 +1,18 @@
+error: type parameters must be declared prior to const parameters
+  --> $DIR/needs-feature.rs:10:26
+   |
+LL | struct A<const N: usize, T=u32>(T);
+   |         -----------------^----- help: reorder the parameters: lifetimes, then types: `<T, const N: usize>`
+
+error[E0658]: const generics are unstable
+  --> $DIR/needs-feature.rs:10:16
+   |
+LL | struct A<const N: usize, T=u32>(T);
+   |                ^
+   |
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/defaults/needs-feature.rs b/src/test/ui/const-generics/defaults/needs-feature.rs
new file mode 100644
index 00000000000..ec02dbf407d
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/needs-feature.rs
@@ -0,0 +1,17 @@
+//[full] run-pass
+// Verifies that having generic parameters after constants is not permitted without the
+// `const_generics` feature.
+// revisions: none min full
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct A<const N: usize, T=u32>(T);
+//[none]~^ ERROR type parameters must be declared prior
+//[none]~| ERROR const generics are unstable
+//[min]~^^^ ERROR type parameters must be declared prior
+
+fn main() {
+  let _: A<3> = A(0);
+}
diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs
new file mode 100644
index 00000000000..b282dfd37cc
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/simple-defaults.rs
@@ -0,0 +1,15 @@
+// run-pass
+// Checks some basic test cases for defaults.
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+struct FixedOutput<'a, const N: usize, T=u32> {
+  out: &'a [T; N],
+}
+
+trait FixedOutputter {
+  fn out(&self) -> FixedOutput<'_, 10>;
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.rs b/src/test/ui/const-generics/derive-debug-array-wrapper.rs
index 36272ae8619..13fd87f1e3e 100644
--- a/src/test/ui/const-generics/derive-debug-array-wrapper.rs
+++ b/src/test/ui/const-generics/derive-debug-array-wrapper.rs
@@ -1,7 +1,10 @@
+// Check that deriving debug on struct with const is permitted.
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(Debug)]
 struct X<const N: usize> {
diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr
deleted file mode 100644
index 8f7ab822554..00000000000
--- a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/derive-debug-array-wrapper.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/different_byref.full.stderr b/src/test/ui/const-generics/different_byref.full.stderr
new file mode 100644
index 00000000000..4463ed7fcdd
--- /dev/null
+++ b/src/test/ui/const-generics/different_byref.full.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/different_byref.rs:13:9
+   |
+LL |     x = Const::<{ [4] }> {};
+   |         ^^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
+   |
+   = note: expected type `[3_usize]`
+              found type `[4_usize]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/different_byref.min.stderr b/src/test/ui/const-generics/different_byref.min.stderr
new file mode 100644
index 00000000000..770491179ab
--- /dev/null
+++ b/src/test/ui/const-generics/different_byref.min.stderr
@@ -0,0 +1,11 @@
+error: using `[usize; 1]` as const generic parameters is forbidden
+  --> $DIR/different_byref.rs:8:23
+   |
+LL | struct Const<const V: [usize; 1]> {}
+   |                       ^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/different_byref.rs b/src/test/ui/const-generics/different_byref.rs
index 78964eb3dee..ec85ed775d4 100644
--- a/src/test/ui/const-generics/different_byref.rs
+++ b/src/test/ui/const-generics/different_byref.rs
@@ -1,11 +1,15 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// Check that different const types are different.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const V: [usize; 1]> {}
+//[min]~^ using `[usize; 1]` as const generic parameters is forbidden
 
 fn main() {
     let mut x = Const::<{ [3] }> {};
     x = Const::<{ [4] }> {};
-    //~^ ERROR mismatched types
-
+    //[full]~^ ERROR mismatched types
 }
diff --git a/src/test/ui/const-generics/different_byref.stderr b/src/test/ui/const-generics/different_byref.stderr
deleted file mode 100644
index a3f331ee811..00000000000
--- a/src/test/ui/const-generics/different_byref.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/different_byref.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0308]: mismatched types
-  --> $DIR/different_byref.rs:8:9
-   |
-LL |     x = Const::<{ [4] }> {};
-   |         ^^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
-   |
-   = note: expected type `[3_usize]`
-              found type `[4_usize]`
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/different_byref_simple.full.stderr b/src/test/ui/const-generics/different_byref_simple.full.stderr
new file mode 100644
index 00000000000..b6729c852ab
--- /dev/null
+++ b/src/test/ui/const-generics/different_byref_simple.full.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/different_byref_simple.rs:12:9
+   |
+LL |     u = ConstUsize::<4> {};
+   |         ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
+   |
+   = note: expected struct `ConstUsize<3_usize>`
+              found struct `ConstUsize<4_usize>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/different_byref_simple.min.stderr b/src/test/ui/const-generics/different_byref_simple.min.stderr
new file mode 100644
index 00000000000..b6729c852ab
--- /dev/null
+++ b/src/test/ui/const-generics/different_byref_simple.min.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/different_byref_simple.rs:12:9
+   |
+LL |     u = ConstUsize::<4> {};
+   |         ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
+   |
+   = note: expected struct `ConstUsize<3_usize>`
+              found struct `ConstUsize<4_usize>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/different_byref_simple.rs b/src/test/ui/const-generics/different_byref_simple.rs
new file mode 100644
index 00000000000..93289f93331
--- /dev/null
+++ b/src/test/ui/const-generics/different_byref_simple.rs
@@ -0,0 +1,14 @@
+// Check that different const types are different.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct ConstUsize<const V: usize> {}
+
+fn main() {
+    let mut u = ConstUsize::<3> {};
+    u = ConstUsize::<4> {};
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/fn-const-param-call.full.stderr b/src/test/ui/const-generics/fn-const-param-call.full.stderr
new file mode 100644
index 00000000000..f1bd8def9ff
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-call.full.stderr
@@ -0,0 +1,14 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:12:25
+   |
+LL | struct Wrapper<const F: fn() -> u32>;
+   |                         ^^^^^^^^^^^
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:14:15
+   |
+LL | impl<const F: fn() -> u32> Wrapper<F> {
+   |               ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/fn-const-param-call.min.stderr b/src/test/ui/const-generics/fn-const-param-call.min.stderr
new file mode 100644
index 00000000000..83acd04e464
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-call.min.stderr
@@ -0,0 +1,20 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:12:25
+   |
+LL | struct Wrapper<const F: fn() -> u32>;
+   |                         ^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:14:15
+   |
+LL | impl<const F: fn() -> u32> Wrapper<F> {
+   |               ^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs
index 90c438b05cb..bba6c1f7a16 100644
--- a/src/test/ui/const-generics/fn-const-param-call.rs
+++ b/src/test/ui/const-generics/fn-const-param-call.rs
@@ -1,5 +1,9 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// Check that functions cannot be used as const parameters.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn function() -> u32 {
     17
diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr
deleted file mode 100644
index b5811243caa..00000000000
--- a/src/test/ui/const-generics/fn-const-param-call.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/fn-const-param-call.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:8:25
-   |
-LL | struct Wrapper<const F: fn() -> u32>;
-   |                         ^^^^^^^^^^^
-
-error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-call.rs:10:15
-   |
-LL | impl<const F: fn() -> u32> Wrapper<F> {
-   |               ^^^^^^^^^^^
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/fn-const-param-infer.full.stderr b/src/test/ui/const-generics/fn-const-param-infer.full.stderr
new file mode 100644
index 00000000000..4bdc9b89af6
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-infer.full.stderr
@@ -0,0 +1,8 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-infer.rs:7:25
+   |
+LL | struct Checked<const F: fn(usize) -> bool>;
+   |                         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/fn-const-param-infer.min.stderr b/src/test/ui/const-generics/fn-const-param-infer.min.stderr
new file mode 100644
index 00000000000..27d1101cbcb
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-infer.min.stderr
@@ -0,0 +1,11 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-infer.rs:7:25
+   |
+LL | struct Checked<const F: fn(usize) -> bool>;
+   |                         ^^^^^^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs
index 14fa3b494b3..3ed75e7b00d 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.rs
+++ b/src/test/ui/const-generics/fn-const-param-infer.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Checked<const F: fn(usize) -> bool>;
 //~^ ERROR: using function pointers as const generic parameters
diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr
deleted file mode 100644
index 7aaa41eb7d7..00000000000
--- a/src/test/ui/const-generics/fn-const-param-infer.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/fn-const-param-infer.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: using function pointers as const generic parameters is forbidden
-  --> $DIR/fn-const-param-infer.rs:4:25
-   |
-LL | struct Checked<const F: fn(usize) -> bool>;
-   |                         ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/fn-taking-const-generic-array.rs b/src/test/ui/const-generics/fn-taking-const-generic-array.rs
index 8e16221ed4b..950684aaa8d 100644
--- a/src/test/ui/const-generics/fn-taking-const-generic-array.rs
+++ b/src/test/ui/const-generics/fn-taking-const-generic-array.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 use std::fmt::Display;
 
diff --git a/src/test/ui/const-generics/fn-taking-const-generic-array.stderr b/src/test/ui/const-generics/fn-taking-const-generic-array.stderr
deleted file mode 100644
index 52fd0a8fec0..00000000000
--- a/src/test/ui/const-generics/fn-taking-const-generic-array.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/fn-taking-const-generic-array.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.full.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.full.stderr
new file mode 100644
index 00000000000..adcaa759963
--- /dev/null
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.full.stderr
@@ -0,0 +1,9 @@
+error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
+  --> $DIR/forbid-non-structural_match-types.rs:15:19
+   |
+LL | struct D<const X: C>;
+   |                   ^ `C` doesn't derive both `PartialEq` and `Eq`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
new file mode 100644
index 00000000000..25aa3540223
--- /dev/null
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
@@ -0,0 +1,27 @@
+error: using `A` as const generic parameters is forbidden
+  --> $DIR/forbid-non-structural_match-types.rs:10:19
+   |
+LL | struct B<const X: A>; // ok
+   |                   ^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `C` as const generic parameters is forbidden
+  --> $DIR/forbid-non-structural_match-types.rs:15:19
+   |
+LL | struct D<const X: C>;
+   |                   ^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
+  --> $DIR/forbid-non-structural_match-types.rs:15:19
+   |
+LL | struct D<const X: C>;
+   |                   ^ `C` doesn't derive both `PartialEq` and `Eq`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.rs b/src/test/ui/const-generics/forbid-non-structural_match-types.rs
index 514e215ba1a..86540db2d03 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.rs
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.rs
@@ -1,13 +1,18 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 #[derive(PartialEq, Eq)]
 struct A;
 
 struct B<const X: A>; // ok
+//[min]~^ ERROR using `A` as const generic parameters is forbidden
 
 struct C;
 
 struct D<const X: C>; //~ ERROR `C` must be annotated with `#[derive(PartialEq, Eq)]`
+//[min]~^ ERROR using `C` as const generic parameters is forbidden
 
 fn main() {}
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
deleted file mode 100644
index 600be64b1e1..00000000000
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/forbid-non-structural_match-types.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
-  --> $DIR/forbid-non-structural_match-types.rs:11:19
-   |
-LL | struct D<const X: C>;
-   |                   ^ `C` doesn't derive both `PartialEq` and `Eq`
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.stderr b/src/test/ui/const-generics/foreign-item-const-parameter.full.stderr
index ee947943af1..0ac51e8c9e6 100644
--- a/src/test/ui/const-generics/foreign-item-const-parameter.stderr
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.full.stderr
@@ -1,14 +1,5 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/foreign-item-const-parameter.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
 error[E0044]: foreign items may not have const parameters
-  --> $DIR/foreign-item-const-parameter.rs:5:5
+  --> $DIR/foreign-item-const-parameter.rs:8:5
    |
 LL |     fn foo<const X: usize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
@@ -16,13 +7,13 @@ LL |     fn foo<const X: usize>();
    = help: replace the const parameters with concrete consts
 
 error[E0044]: foreign items may not have type or const parameters
-  --> $DIR/foreign-item-const-parameter.rs:7:5
+  --> $DIR/foreign-item-const-parameter.rs:10:5
    |
 LL |     fn bar<T, const X: usize>(_: T);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
    |
    = help: replace the type or const parameters with concrete types or consts
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0044`.
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.min.stderr b/src/test/ui/const-generics/foreign-item-const-parameter.min.stderr
new file mode 100644
index 00000000000..0ac51e8c9e6
--- /dev/null
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.min.stderr
@@ -0,0 +1,19 @@
+error[E0044]: foreign items may not have const parameters
+  --> $DIR/foreign-item-const-parameter.rs:8:5
+   |
+LL |     fn foo<const X: usize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
+   |
+   = help: replace the const parameters with concrete consts
+
+error[E0044]: foreign items may not have type or const parameters
+  --> $DIR/foreign-item-const-parameter.rs:10:5
+   |
+LL |     fn bar<T, const X: usize>(_: T);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
+   |
+   = help: replace the type or const parameters with concrete types or consts
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0044`.
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.rs b/src/test/ui/const-generics/foreign-item-const-parameter.rs
index 41113780de3..44b6d0332c3 100644
--- a/src/test/ui/const-generics/foreign-item-const-parameter.rs
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 extern "C" {
     fn foo<const X: usize>(); //~ ERROR foreign items may not have const parameters
diff --git a/src/test/ui/const-generics/impl-const-generic-struct.rs b/src/test/ui/const-generics/impl-const-generic-struct.rs
index 4c2aee59ffe..05cabc46baa 100644
--- a/src/test/ui/const-generics/impl-const-generic-struct.rs
+++ b/src/test/ui/const-generics/impl-const-generic-struct.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct S<const X: u32>;
 
diff --git a/src/test/ui/const-generics/impl-const-generic-struct.stderr b/src/test/ui/const-generics/impl-const-generic-struct.stderr
deleted file mode 100644
index 9d68df07ce6..00000000000
--- a/src/test/ui/const-generics/impl-const-generic-struct.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/impl-const-generic-struct.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.full.stderr b/src/test/ui/const-generics/incorrect-number-of-const-args.full.stderr
new file mode 100644
index 00000000000..6b902e2d658
--- /dev/null
+++ b/src/test/ui/const-generics/incorrect-number-of-const-args.full.stderr
@@ -0,0 +1,15 @@
+error[E0107]: wrong number of const arguments: expected 2, found 1
+  --> $DIR/incorrect-number-of-const-args.rs:12:5
+   |
+LL |     foo::<0>();
+   |     ^^^^^^^^ expected 2 const arguments
+
+error[E0107]: wrong number of const arguments: expected 2, found 3
+  --> $DIR/incorrect-number-of-const-args.rs:13:17
+   |
+LL |     foo::<0, 0, 0>();
+   |                 ^ unexpected const argument
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.min.stderr b/src/test/ui/const-generics/incorrect-number-of-const-args.min.stderr
new file mode 100644
index 00000000000..6b902e2d658
--- /dev/null
+++ b/src/test/ui/const-generics/incorrect-number-of-const-args.min.stderr
@@ -0,0 +1,15 @@
+error[E0107]: wrong number of const arguments: expected 2, found 1
+  --> $DIR/incorrect-number-of-const-args.rs:12:5
+   |
+LL |     foo::<0>();
+   |     ^^^^^^^^ expected 2 const arguments
+
+error[E0107]: wrong number of const arguments: expected 2, found 3
+  --> $DIR/incorrect-number-of-const-args.rs:13:17
+   |
+LL |     foo::<0, 0, 0>();
+   |                 ^ unexpected const argument
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.rs b/src/test/ui/const-generics/incorrect-number-of-const-args.rs
index cea64654e11..f7bdf761f7d 100644
--- a/src/test/ui/const-generics/incorrect-number-of-const-args.rs
+++ b/src/test/ui/const-generics/incorrect-number-of-const-args.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const X: usize, const Y: usize>() -> usize {
     0
diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.stderr b/src/test/ui/const-generics/incorrect-number-of-const-args.stderr
deleted file mode 100644
index 51064d7f90f..00000000000
--- a/src/test/ui/const-generics/incorrect-number-of-const-args.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/incorrect-number-of-const-args.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0107]: wrong number of const arguments: expected 2, found 1
-  --> $DIR/incorrect-number-of-const-args.rs:9:5
-   |
-LL |     foo::<0>();
-   |     ^^^^^^^^ expected 2 const arguments
-
-error[E0107]: wrong number of const arguments: expected 2, found 3
-  --> $DIR/incorrect-number-of-const-args.rs:10:17
-   |
-LL |     foo::<0, 0, 0>();
-   |                 ^ unexpected const argument
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/infer_arg_from_pat.rs b/src/test/ui/const-generics/infer_arg_from_pat.rs
index 7e8152dacc4..609fdb35cf1 100644
--- a/src/test/ui/const-generics/infer_arg_from_pat.rs
+++ b/src/test/ui/const-generics/infer_arg_from_pat.rs
@@ -1,8 +1,11 @@
 // run-pass
 //
 // see issue #70529
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize> {
     arr: [u8; N],
diff --git a/src/test/ui/const-generics/infer_arg_from_pat.stderr b/src/test/ui/const-generics/infer_arg_from_pat.stderr
deleted file mode 100644
index f52e5e49a3b..00000000000
--- a/src/test/ui/const-generics/infer_arg_from_pat.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/infer_arg_from_pat.rs:4:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/infer_arr_len_from_pat.rs b/src/test/ui/const-generics/infer_arr_len_from_pat.rs
index cede9ea045d..cbf48e3d249 100644
--- a/src/test/ui/const-generics/infer_arr_len_from_pat.rs
+++ b/src/test/ui/const-generics/infer_arr_len_from_pat.rs
@@ -1,8 +1,11 @@
 // check-pass
 //
 // see issue #70529
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn as_chunks<const N: usize>() -> [u8; N] {
     loop {}
diff --git a/src/test/ui/const-generics/infer_arr_len_from_pat.stderr b/src/test/ui/const-generics/infer_arr_len_from_pat.stderr
deleted file mode 100644
index dfadfbb1663..00000000000
--- a/src/test/ui/const-generics/infer_arr_len_from_pat.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/infer_arr_len_from_pat.rs:4:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.rs b/src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.rs
index 952e05bac30..bdbf338295c 100644
--- a/src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.rs
+++ b/src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.rs
@@ -1,7 +1,9 @@
 // check-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn takes_closure_of_array_3<F>(f: F) where F: Fn([i32; 3]) {
     f([1, 2, 3]);
@@ -15,4 +17,7 @@ fn returns_closure_of_array_3() -> impl Fn([i32; 3]) {
     |_| {}
 }
 
-fn main() {}
+fn main() {
+    takes_closure_of_array_3(returns_closure_of_array_3());
+    takes_closure_of_array_3_apit(returns_closure_of_array_3());
+}
diff --git a/src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.stderr b/src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.stderr
deleted file mode 100644
index aadd10e5cca..00000000000
--- a/src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/integer-literal-generic-arg-in-where-clause.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.full.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.full.stderr
new file mode 100644
index 00000000000..8855f187e97
--- /dev/null
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.full.stderr
@@ -0,0 +1,18 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-61522-array-len-succ.rs:7:40
+   |
+LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+   |                                        ^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-61522-array-len-succ.rs:12:24
+   |
+LL |     fn inner(&self) -> &[u8; COUNT + 1] {
+   |                        ^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
new file mode 100644
index 00000000000..a1b1a095041
--- /dev/null
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
@@ -0,0 +1,18 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-61522-array-len-succ.rs:7:45
+   |
+LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+   |                                             ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT`
+   |
+   = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-61522-array-len-succ.rs:12:30
+   |
+LL |     fn inner(&self) -> &[u8; COUNT + 1] {
+   |                              ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT`
+   |
+   = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.rs b/src/test/ui/const-generics/issue-61522-array-len-succ.rs
index 7c8cdeece87..81443b90d61 100644
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.rs
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.rs
@@ -1,12 +1,17 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
-//~^ ERROR constant expression depends on a generic parameter
+//[full]~^ ERROR constant expression depends on a generic parameter
+//[min]~^^ ERROR generic parameters must not be used
 
 impl<const COUNT: usize> MyArray<COUNT> {
     fn inner(&self) -> &[u8; COUNT + 1] {
-        //~^ ERROR constant expression depends on a generic parameter
+        //[full]~^ ERROR constant expression depends on a generic parameter
+        //[min]~^^ ERROR generic parameters must not be used
         &self.0
     }
 }
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.stderr
deleted file mode 100644
index a1fbd5f2025..00000000000
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61522-array-len-succ.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-61522-array-len-succ.rs:4:40
-   |
-LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
-   |                                        ^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-61522-array-len-succ.rs:8:24
-   |
-LL |     fn inner(&self) -> &[u8; COUNT + 1] {
-   |                        ^^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
new file mode 100644
index 00000000000..3ff17ddb3bc
--- /dev/null
+++ b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
@@ -0,0 +1,11 @@
+error: using `&'static str` as const generic parameters is forbidden
+  --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:9:25
+   |
+LL | trait Trait<const NAME: &'static str> {
+   |                         ^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs
index 74f036e6d89..d458a366fb3 100644
--- a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs
+++ b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs
@@ -1,9 +1,13 @@
-// check-pass
+//[full] check-pass
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
 
 trait Trait<const NAME: &'static str> {
+//[min]~^ ERROR using `&'static str` as const generic parameters is forbidden
     type Assoc;
 }
 
diff --git a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.stderr b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.stderr
deleted file mode 100644
index 720420d9cd6..00000000000
--- a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs b/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs
index bda9ce8767d..eab63d3a6e6 100644
--- a/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs
+++ b/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs
@@ -1,8 +1,10 @@
 // aux-build:impl-const.rs
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 extern crate impl_const;
 
diff --git a/src/test/ui/const-generics/issue-70180-1-stalled_on.rs b/src/test/ui/const-generics/issue-70180-1-stalled_on.rs
index ff2a5250263..9cfa57006d5 100644
--- a/src/test/ui/const-generics/issue-70180-1-stalled_on.rs
+++ b/src/test/ui/const-generics/issue-70180-1-stalled_on.rs
@@ -1,6 +1,9 @@
 // build-pass
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub fn works() {
     let array/*: [_; _]*/ = default_array();
diff --git a/src/test/ui/const-generics/issue-70180-2-stalled_on.rs b/src/test/ui/const-generics/issue-70180-2-stalled_on.rs
index 83338668f4f..bbde404966c 100644
--- a/src/test/ui/const-generics/issue-70180-2-stalled_on.rs
+++ b/src/test/ui/const-generics/issue-70180-2-stalled_on.rs
@@ -1,6 +1,9 @@
 // build-pass
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn works() {
     let array/*: [u8; _]*/ = default_byte_array();
diff --git a/src/test/ui/const-generics/issue-71986.rs b/src/test/ui/const-generics/issue-71986.rs
index 048ed18c927..d4c962452d1 100644
--- a/src/test/ui/const-generics/issue-71986.rs
+++ b/src/test/ui/const-generics/issue-71986.rs
@@ -1,6 +1,9 @@
 // check-pass
-#![allow(incomplete_features)]
-#![feature(const_generics)]
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub trait Foo<const B: bool> {}
 pub fn bar<T: Foo<{ true }>>() {}
diff --git a/src/test/ui/const-generics/mut-ref-const-param-array.rs b/src/test/ui/const-generics/mut-ref-const-param-array.rs
index 9ca1f4552f5..cf24cbe7e82 100644
--- a/src/test/ui/const-generics/mut-ref-const-param-array.rs
+++ b/src/test/ui/const-generics/mut-ref-const-param-array.rs
@@ -1,7 +1,10 @@
 // run-pass
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
 
 use std::ops::AddAssign;
 
diff --git a/src/test/ui/const-generics/mut-ref-const-param-array.stderr b/src/test/ui/const-generics/mut-ref-const-param-array.stderr
deleted file mode 100644
index acbc2df1d74..00000000000
--- a/src/test/ui/const-generics/mut-ref-const-param-array.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/mut-ref-const-param-array.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/nested-type.stderr b/src/test/ui/const-generics/nested-type.full.stderr
index da0e8032404..012b8fe587b 100644
--- a/src/test/ui/const-generics/nested-type.stderr
+++ b/src/test/ui/const-generics/nested-type.full.stderr
@@ -1,154 +1,154 @@
 error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:4:1
+  --> $DIR/nested-type.rs:7:1
    |
 LL | struct Foo<const N: [u8; {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:4:18
+  --> $DIR/nested-type.rs:7:18
    |
 LL | struct Foo<const N: [u8; {
    |                  ^
 note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:7:5
+  --> $DIR/nested-type.rs:11:5
    |
 LL |     struct Foo<const N: usize>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing the variances for items in this crate...
    = note: ...which again requires computing type of `Foo`, completing the cycle
 note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:1:1
+  --> $DIR/nested-type.rs:3:1
    |
-LL | / #![feature(const_generics)]
-LL | | #![allow(incomplete_features)]
+LL | / #![cfg_attr(full, feature(const_generics))]
+LL | | #![cfg_attr(full, allow(incomplete_features))]
+LL | | #![cfg_attr(min, feature(min_const_generics))]
 LL | |
-LL | | struct Foo<const N: [u8; {
 ...  |
 LL | |
 LL | | fn main() {}
    | |____________^
 
 error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:4:1
+  --> $DIR/nested-type.rs:7:1
    |
 LL | struct Foo<const N: [u8; {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:4:18
+  --> $DIR/nested-type.rs:7:18
    |
 LL | struct Foo<const N: [u8; {
    |                  ^
 note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:4:26
+  --> $DIR/nested-type.rs:7:26
    |
 LL |   struct Foo<const N: [u8; {
    |  __________________________^
 LL | |
 LL | |
-LL | |     struct Foo<const N: usize>;
+LL | |
 ...  |
 LL | |     Foo::<17>::value()
 LL | | }]>;
    | |_^
 note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:7:5
+  --> $DIR/nested-type.rs:11:5
    |
 LL |     struct Foo<const N: usize>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing the variances for items in this crate...
    = note: ...which again requires computing type of `Foo`, completing the cycle
 note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:1:1
+  --> $DIR/nested-type.rs:3:1
    |
-LL | / #![feature(const_generics)]
-LL | | #![allow(incomplete_features)]
+LL | / #![cfg_attr(full, feature(const_generics))]
+LL | | #![cfg_attr(full, allow(incomplete_features))]
+LL | | #![cfg_attr(min, feature(min_const_generics))]
 LL | |
-LL | | struct Foo<const N: [u8; {
 ...  |
 LL | |
 LL | | fn main() {}
diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr
new file mode 100644
index 00000000000..ebe818785ac
--- /dev/null
+++ b/src/test/ui/const-generics/nested-type.min.stderr
@@ -0,0 +1,175 @@
+error: using `[u8; _]` as const generic parameters is forbidden
+  --> $DIR/nested-type.rs:7:21
+   |
+LL |   struct Foo<const N: [u8; {
+   |  _____________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |__^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error[E0391]: cycle detected when computing type of `Foo`
+  --> $DIR/nested-type.rs:7:1
+   |
+LL | struct Foo<const N: [u8; {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing type of `Foo::N`...
+  --> $DIR/nested-type.rs:7:18
+   |
+LL | struct Foo<const N: [u8; {
+   |                  ^
+note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires const-evaluating `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires type-checking `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
+  --> $DIR/nested-type.rs:11:5
+   |
+LL |     struct Foo<const N: usize>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing the variances for items in this crate...
+   = note: ...which again requires computing type of `Foo`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/nested-type.rs:3:1
+   |
+LL | / #![cfg_attr(full, feature(const_generics))]
+LL | | #![cfg_attr(full, allow(incomplete_features))]
+LL | | #![cfg_attr(min, feature(min_const_generics))]
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error[E0391]: cycle detected when computing type of `Foo`
+  --> $DIR/nested-type.rs:7:1
+   |
+LL | struct Foo<const N: [u8; {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing type of `Foo::N`...
+  --> $DIR/nested-type.rs:7:18
+   |
+LL | struct Foo<const N: [u8; {
+   |                  ^
+note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires const-evaluating `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires type-checking `Foo::{{constant}}#0`...
+  --> $DIR/nested-type.rs:7:26
+   |
+LL |   struct Foo<const N: [u8; {
+   |  __________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     Foo::<17>::value()
+LL | | }]>;
+   | |_^
+note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
+  --> $DIR/nested-type.rs:11:5
+   |
+LL |     struct Foo<const N: usize>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing the variances for items in this crate...
+   = note: ...which again requires computing type of `Foo`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/nested-type.rs:3:1
+   |
+LL | / #![cfg_attr(full, feature(const_generics))]
+LL | | #![cfg_attr(full, allow(incomplete_features))]
+LL | | #![cfg_attr(min, feature(min_const_generics))]
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs
index 12ea850c8f6..98a5a0dd3d8 100644
--- a/src/test/ui/const-generics/nested-type.rs
+++ b/src/test/ui/const-generics/nested-type.rs
@@ -1,9 +1,13 @@
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const N: [u8; {
 //~^ ERROR cycle detected
 //~| ERROR cycle detected
+//[min]~| ERROR using `[u8; _]` as const generic
     struct Foo<const N: usize>;
 
     impl<const N: usize> Foo<N> {
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr
index 571be91683b..3dccfd73dcc 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.stderr
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr
@@ -1,5 +1,5 @@
 error: type parameters with a default must be trailing
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:12
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:12
    |
 LL | struct Bar<T = [u8; N], const N: usize>(T);
    |            ^
@@ -7,25 +7,16 @@ LL | struct Bar<T = [u8; N], const N: usize>(T);
    = note: using type defaults and const parameters in the same parameter list is currently not permitted
 
 error: constant values inside of type parameter defaults must not depend on generic parameters
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:3:44
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
    |
 LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
    |                                            ^ the anonymous constant must not depend on the parameter `T`
 
 error: constant values inside of type parameter defaults must not depend on generic parameters
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:21
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
    |
 LL | struct Bar<T = [u8; N], const N: usize>(T);
    |                     ^ the anonymous constant must not depend on the parameter `N`
 
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
new file mode 100644
index 00000000000..461822a9608
--- /dev/null
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
@@ -0,0 +1,24 @@
+error: type parameters with a default must be trailing
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:12
+   |
+LL | struct Bar<T = [u8; N], const N: usize>(T);
+   |            ^
+   |
+   = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
+   |
+LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
+   |                                            ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |
+   = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+
+error: constant values inside of type parameter defaults must not depend on generic parameters
+  --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
+   |
+LL | struct Bar<T = [u8; N], const N: usize>(T);
+   |                     ^ the anonymous constant must not depend on the parameter `N`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
index 84bbea5b880..e52773c78db 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
@@ -1,7 +1,12 @@
-#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
-//~^ ERROR constant values inside of type parameter defaults
+//[full]~^ ERROR constant values inside of type parameter defaults
+//[min]~^^ ERROR generic parameters must not be used inside of non trivial
 
 // FIXME(const_generics:defaults): We still don't know how to we deal with type defaults.
 struct Bar<T = [u8; N], const N: usize>(T);
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr
new file mode 100644
index 00000000000..ffaab51f766
--- /dev/null
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr
@@ -0,0 +1,14 @@
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:10:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:12:15
+   |
+LL | impl<const P: *const u32> Const<P> {
+   |               ^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr
new file mode 100644
index 00000000000..dc4bb8b0f04
--- /dev/null
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr
@@ -0,0 +1,20 @@
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:10:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:12:15
+   |
+LL | impl<const P: *const u32> Const<P> {
+   |               ^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
index 97ca9d6a44c..20cc62ebc17 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
@@ -1,5 +1,9 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// Checks that pointers must not be used as the type of const params.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 const A: u32 = 3;
 
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
deleted file mode 100644
index 1ce8bb9c054..00000000000
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-ptr-const-param-deref.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:6:23
-   |
-LL | struct Const<const P: *const u32>;
-   |                       ^^^^^^^^^^
-
-error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param-deref.rs:8:15
-   |
-LL | impl<const P: *const u32> Const<P> {
-   |               ^^^^^^^^^^
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.full.stderr b/src/test/ui/const-generics/raw-ptr-const-param.full.stderr
new file mode 100644
index 00000000000..d317aa0f585
--- /dev/null
+++ b/src/test/ui/const-generics/raw-ptr-const-param.full.stderr
@@ -0,0 +1,8 @@
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param.rs:7:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.min.stderr b/src/test/ui/const-generics/raw-ptr-const-param.min.stderr
new file mode 100644
index 00000000000..f387974a21a
--- /dev/null
+++ b/src/test/ui/const-generics/raw-ptr-const-param.min.stderr
@@ -0,0 +1,11 @@
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param.rs:7:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs
index 237b410e073..36e593aa210 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param.rs
+++ b/src/test/ui/const-generics/raw-ptr-const-param.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr
deleted file mode 100644
index 6e64f8a327f..00000000000
--- a/src/test/ui/const-generics/raw-ptr-const-param.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-ptr-const-param.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: using raw pointers as const generic parameters is forbidden
-  --> $DIR/raw-ptr-const-param.rs:4:23
-   |
-LL | struct Const<const P: *const u32>;
-   |                       ^^^^^^^^^^
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.full.stderr
index cc21f197e08..d06da2ef063 100644
--- a/src/test/ui/const-generics/slice-const-param-mismatch.stderr
+++ b/src/test/ui/const-generics/slice-const-param-mismatch.full.stderr
@@ -1,14 +1,5 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/slice-const-param-mismatch.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:9:35
+  --> $DIR/slice-const-param-mismatch.rs:15:35
    |
 LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
    |            --------------------   ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
@@ -19,7 +10,7 @@ LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
               found struct `ConstString<"World">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:11:33
+  --> $DIR/slice-const-param-mismatch.rs:17:33
    |
 LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
    |            -------------------   ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
@@ -30,7 +21,7 @@ LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
               found struct `ConstString<"ℇ㇈↥">`
 
 error[E0308]: mismatched types
-  --> $DIR/slice-const-param-mismatch.rs:13:33
+  --> $DIR/slice-const-param-mismatch.rs:19:33
    |
 LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
    |            ------------------   ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
@@ -40,6 +31,6 @@ LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
    = note: expected struct `ConstBytes<b"AAA">`
               found struct `ConstBytes<b"BBB">`
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
new file mode 100644
index 00000000000..e86f885b9bb
--- /dev/null
+++ b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
@@ -0,0 +1,20 @@
+error: using `&'static str` as const generic parameters is forbidden
+  --> $DIR/slice-const-param-mismatch.rs:8:29
+   |
+LL | struct ConstString<const T: &'static str>;
+   |                             ^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static [u8]` as const generic parameters is forbidden
+  --> $DIR/slice-const-param-mismatch.rs:10:28
+   |
+LL | struct ConstBytes<const T: &'static [u8]>;
+   |                            ^^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.rs b/src/test/ui/const-generics/slice-const-param-mismatch.rs
index 4f321b02b82..0f8ae9bac4a 100644
--- a/src/test/ui/const-generics/slice-const-param-mismatch.rs
+++ b/src/test/ui/const-generics/slice-const-param-mismatch.rs
@@ -1,14 +1,20 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
 
 struct ConstString<const T: &'static str>;
+//[min]~^ ERROR
 struct ConstBytes<const T: &'static [u8]>;
+//[min]~^ ERROR
 
 pub fn main() {
     let _: ConstString<"Hello"> = ConstString::<"Hello">;
-    let _: ConstString<"Hello"> = ConstString::<"World">; //~ ERROR mismatched types
+    let _: ConstString<"Hello"> = ConstString::<"World">; //[full]~ ERROR mismatched types
     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↦">;
-    let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //~ ERROR mismatched types
+    let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //[full]~ ERROR mismatched types
     let _: ConstBytes<b"AAA"> = ConstBytes::<{&[0x41, 0x41, 0x41]}>;
-    let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; //~ ERROR mismatched types
+    let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; //[full]~ ERROR mismatched types
 }
diff --git a/src/test/ui/const-generics/slice-const-param.min.stderr b/src/test/ui/const-generics/slice-const-param.min.stderr
new file mode 100644
index 00000000000..e2ffc67c357
--- /dev/null
+++ b/src/test/ui/const-generics/slice-const-param.min.stderr
@@ -0,0 +1,20 @@
+error: using `&'static str` as const generic parameters is forbidden
+  --> $DIR/slice-const-param.rs:8:40
+   |
+LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
+   |                                        ^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static [u8]` as const generic parameters is forbidden
+  --> $DIR/slice-const-param.rs:13:41
+   |
+LL | pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
+   |                                         ^^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/slice-const-param.rs b/src/test/ui/const-generics/slice-const-param.rs
index 9668f7ddabb..1b6d2f6216c 100644
--- a/src/test/ui/const-generics/slice-const-param.rs
+++ b/src/test/ui/const-generics/slice-const-param.rs
@@ -1,13 +1,17 @@
-// run-pass
+//[full] run-pass
+// revisions: min full
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub fn function_with_str<const STRING: &'static str>() -> &'static str {
+    //[min]~^ ERROR using `&'static str` as const
     STRING
 }
 
 pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
+    //[min]~^ ERROR using `&'static [u8]` as const
     BYTES
 }
 
diff --git a/src/test/ui/const-generics/slice-const-param.stderr b/src/test/ui/const-generics/slice-const-param.stderr
deleted file mode 100644
index 524bd41a669..00000000000
--- a/src/test/ui/const-generics/slice-const-param.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/slice-const-param.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.full.stderr b/src/test/ui/const-generics/struct-with-invalid-const-param.full.stderr
new file mode 100644
index 00000000000..e73a297c878
--- /dev/null
+++ b/src/test/ui/const-generics/struct-with-invalid-const-param.full.stderr
@@ -0,0 +1,9 @@
+error[E0573]: expected type, found const parameter `C`
+  --> $DIR/struct-with-invalid-const-param.rs:8:23
+   |
+LL | struct S<const C: u8>(C);
+   |                       ^ not a type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.min.stderr b/src/test/ui/const-generics/struct-with-invalid-const-param.min.stderr
new file mode 100644
index 00000000000..e73a297c878
--- /dev/null
+++ b/src/test/ui/const-generics/struct-with-invalid-const-param.min.stderr
@@ -0,0 +1,9 @@
+error[E0573]: expected type, found const parameter `C`
+  --> $DIR/struct-with-invalid-const-param.rs:8:23
+   |
+LL | struct S<const C: u8>(C);
+   |                       ^ not a type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.rs b/src/test/ui/const-generics/struct-with-invalid-const-param.rs
index 0b00481d903..f0122ace3ae 100644
--- a/src/test/ui/const-generics/struct-with-invalid-const-param.rs
+++ b/src/test/ui/const-generics/struct-with-invalid-const-param.rs
@@ -1,5 +1,9 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// Checks that a const param cannot be stored in a struct.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct S<const C: u8>(C); //~ ERROR expected type, found const parameter
 
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/trait-const-args.rs b/src/test/ui/const-generics/trait-const-args.rs
index b60d7e89651..b66d79845f9 100644
--- a/src/test/ui/const-generics/trait-const-args.rs
+++ b/src/test/ui/const-generics/trait-const-args.rs
@@ -1,6 +1,9 @@
 // check-pass
-#![allow(incomplete_features)]
-#![feature(const_generics)]
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const N: usize>;
 trait Foo<const N: usize> {}
diff --git a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs
index 1aed9cfe927..e041e9709d0 100644
--- a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs
+++ b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem::MaybeUninit;
 
diff --git a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr
deleted file mode 100644
index 6077fe5b1ed..00000000000
--- a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/transparent-maybeunit-array-wrapper.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/type-after-const-ok.rs b/src/test/ui/const-generics/type-after-const-ok.rs
new file mode 100644
index 00000000000..fc977d6617c
--- /dev/null
+++ b/src/test/ui/const-generics/type-after-const-ok.rs
@@ -0,0 +1,10 @@
+// run-pass
+// Verifies that having generic parameters after constants is permitted
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+#[allow(dead_code)]
+struct A<const N: usize, T>(T);
+
+fn main() {}
diff --git a/src/test/ui/const-generics/type_of_anon_const.rs b/src/test/ui/const-generics/type_of_anon_const.rs
index 588c7b9523a..f424fd03341 100644
--- a/src/test/ui/const-generics/type_of_anon_const.rs
+++ b/src/test/ui/const-generics/type_of_anon_const.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 trait T<const A: usize> {
     fn l<const N: bool>() -> usize;
diff --git a/src/test/ui/const-generics/type_of_anon_const.stderr b/src/test/ui/const-generics/type_of_anon_const.stderr
deleted file mode 100644
index 8afed0d3986..00000000000
--- a/src/test/ui/const-generics/type_of_anon_const.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/type_of_anon_const.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/uninferred-consts.full.stderr b/src/test/ui/const-generics/uninferred-consts.full.stderr
new file mode 100644
index 00000000000..2c5af9e65f8
--- /dev/null
+++ b/src/test/ui/const-generics/uninferred-consts.full.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/uninferred-consts.rs:14:5
+   |
+LL |     Foo.foo();
+   |     ^^^^^^^^^
+   |
+   = note: unable to infer the value of a const parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/uninferred-consts.min.stderr b/src/test/ui/const-generics/uninferred-consts.min.stderr
new file mode 100644
index 00000000000..2c5af9e65f8
--- /dev/null
+++ b/src/test/ui/const-generics/uninferred-consts.min.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/uninferred-consts.rs:14:5
+   |
+LL |     Foo.foo();
+   |     ^^^^^^^^^
+   |
+   = note: unable to infer the value of a const parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/uninferred-consts.rs b/src/test/ui/const-generics/uninferred-consts.rs
index 3b2bb49197d..ec5b3ffe544 100644
--- a/src/test/ui/const-generics/uninferred-consts.rs
+++ b/src/test/ui/const-generics/uninferred-consts.rs
@@ -1,5 +1,9 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// Test that we emit an error if we cannot properly infer a constant.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 // taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
 struct Foo;
diff --git a/src/test/ui/const-generics/uninferred-consts.stderr b/src/test/ui/const-generics/uninferred-consts.stderr
deleted file mode 100644
index a3620084a42..00000000000
--- a/src/test/ui/const-generics/uninferred-consts.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/uninferred-consts.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0282]: type annotations needed
-  --> $DIR/uninferred-consts.rs:10:5
-   |
-LL |     Foo.foo();
-   |     ^^^^^^^^^
-   |
-   = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/unknown_adt.stderr b/src/test/ui/const-generics/unknown_adt.full.stderr
index b2e287b762c..94f3165eaec 100644
--- a/src/test/ui/const-generics/unknown_adt.stderr
+++ b/src/test/ui/const-generics/unknown_adt.full.stderr
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `UnknownStruct` in this scope
-  --> $DIR/unknown_adt.rs:5:12
+  --> $DIR/unknown_adt.rs:8:12
    |
 LL |     let _: UnknownStruct<7>;
    |            ^^^^^^^^^^^^^ not found in this scope
diff --git a/src/test/ui/const-generics/unknown_adt.min.stderr b/src/test/ui/const-generics/unknown_adt.min.stderr
new file mode 100644
index 00000000000..94f3165eaec
--- /dev/null
+++ b/src/test/ui/const-generics/unknown_adt.min.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `UnknownStruct` in this scope
+  --> $DIR/unknown_adt.rs:8:12
+   |
+LL |     let _: UnknownStruct<7>;
+   |            ^^^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/const-generics/unknown_adt.rs b/src/test/ui/const-generics/unknown_adt.rs
index 0ba9945b399..c6131402aeb 100644
--- a/src/test/ui/const-generics/unknown_adt.rs
+++ b/src/test/ui/const-generics/unknown_adt.rs
@@ -1,5 +1,8 @@
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn main() {
     let _: UnknownStruct<7>;
diff --git a/src/test/ui/const-generics/unused-const-param.rs b/src/test/ui/const-generics/unused-const-param.rs
index d9292efc21b..3c305167b4b 100644
--- a/src/test/ui/const-generics/unused-const-param.rs
+++ b/src/test/ui/const-generics/unused-const-param.rs
@@ -1,7 +1,9 @@
 // check-pass
+// revisions: full min
 
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<const N: usize>; // ok
 
diff --git a/src/test/ui/const-generics/unused-const-param.stderr b/src/test/ui/const-generics/unused-const-param.stderr
deleted file mode 100644
index be015a689ae..00000000000
--- a/src/test/ui/const-generics/unused-const-param.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/unused-const-param.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
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/const-generics/unused_braces.full.fixed b/src/test/ui/const-generics/unused_braces.full.fixed
new file mode 100644
index 00000000000..1b075ade16a
--- /dev/null
+++ b/src/test/ui/const-generics/unused_braces.full.fixed
@@ -0,0 +1,17 @@
+// check-pass
+// run-rustfix
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+#![warn(unused_braces)]
+
+
+struct A<const N: usize>;
+
+fn main() {
+    let _: A<7>; // ok
+    let _: A<7>; //~ WARN unnecessary braces
+    let _: A<{ 3 + 5 }>; // ok
+}
diff --git a/src/test/ui/const-generics/unused_braces.stderr b/src/test/ui/const-generics/unused_braces.full.stderr
index 618698a3234..1752779a60a 100644
--- a/src/test/ui/const-generics/unused_braces.stderr
+++ b/src/test/ui/const-generics/unused_braces.full.stderr
@@ -1,11 +1,11 @@
 warning: unnecessary braces around const expression
-  --> $DIR/unused_braces.rs:13:14
+  --> $DIR/unused_braces.rs:15:14
    |
 LL |     let _: A<{ 7 }>;
    |              ^^^^^ help: remove these braces
    |
 note: the lint level is defined here
-  --> $DIR/unused_braces.rs:5:9
+  --> $DIR/unused_braces.rs:8:9
    |
 LL | #![warn(unused_braces)]
    |         ^^^^^^^^^^^^^
diff --git a/src/test/ui/const-generics/unused_braces.min.fixed b/src/test/ui/const-generics/unused_braces.min.fixed
new file mode 100644
index 00000000000..1b075ade16a
--- /dev/null
+++ b/src/test/ui/const-generics/unused_braces.min.fixed
@@ -0,0 +1,17 @@
+// check-pass
+// run-rustfix
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+#![warn(unused_braces)]
+
+
+struct A<const N: usize>;
+
+fn main() {
+    let _: A<7>; // ok
+    let _: A<7>; //~ WARN unnecessary braces
+    let _: A<{ 3 + 5 }>; // ok
+}
diff --git a/src/test/ui/const-generics/unused_braces.min.stderr b/src/test/ui/const-generics/unused_braces.min.stderr
new file mode 100644
index 00000000000..1752779a60a
--- /dev/null
+++ b/src/test/ui/const-generics/unused_braces.min.stderr
@@ -0,0 +1,14 @@
+warning: unnecessary braces around const expression
+  --> $DIR/unused_braces.rs:15:14
+   |
+LL |     let _: A<{ 7 }>;
+   |              ^^^^^ help: remove these braces
+   |
+note: the lint level is defined here
+  --> $DIR/unused_braces.rs:8:9
+   |
+LL | #![warn(unused_braces)]
+   |         ^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/const-generics/unused_braces.rs b/src/test/ui/const-generics/unused_braces.rs
index c3e02b45ed5..31c4caf7ab8 100644
--- a/src/test/ui/const-generics/unused_braces.rs
+++ b/src/test/ui/const-generics/unused_braces.rs
@@ -1,10 +1,12 @@
 // check-pass
 // run-rustfix
+// revisions: full min
 
-#![allow(incomplete_features)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 #![warn(unused_braces)]
 
-#![feature(const_generics)]
 
 struct A<const N: usize>;
 
diff --git a/src/test/ui/const-generics/wf-misc.full.stderr b/src/test/ui/const-generics/wf-misc.full.stderr
new file mode 100644
index 00000000000..4af48fa1590
--- /dev/null
+++ b/src/test/ui/const-generics/wf-misc.full.stderr
@@ -0,0 +1,18 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/wf-misc.rs:9:12
+   |
+LL |     let _: [u8; N + 1];
+   |            ^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/wf-misc.rs:17:12
+   |
+LL |     let _: Const::<{N + 1}>;
+   |            ^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/wf-misc.min.stderr b/src/test/ui/const-generics/wf-misc.min.stderr
new file mode 100644
index 00000000000..f2acb8fc06e
--- /dev/null
+++ b/src/test/ui/const-generics/wf-misc.min.stderr
@@ -0,0 +1,18 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/wf-misc.rs:9:17
+   |
+LL |     let _: [u8; N + 1];
+   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/wf-misc.rs:17:21
+   |
+LL |     let _: Const::<{N + 1}>;
+   |                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs
index 4ff1b9e2da5..e6f7a9963e8 100644
--- a/src/test/ui/const-generics/wf-misc.rs
+++ b/src/test/ui/const-generics/wf-misc.rs
@@ -1,16 +1,22 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// Tests miscellaneous well-formedness examples.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub fn arr_len<const N: usize>() {
     let _: [u8; N + 1];
-    //~^ ERROR constant expression depends on a generic parameter
+    //[full]~^ ERROR constant expression depends on a generic parameter
+    //[min]~^^ ERROR generic parameters must not be used inside of non trivial
 }
 
 struct Const<const N: usize>;
 
 pub fn func_call<const N: usize>() {
     let _: Const::<{N + 1}>;
-    //~^ ERROR constant expression depends on a generic parameter
+    //[full]~^ ERROR constant expression depends on a generic parameter
+    //[min]~^^ ERROR generic parameters must not be used inside of non trivial
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/wf-misc.stderr b/src/test/ui/const-generics/wf-misc.stderr
deleted file mode 100644
index 03f2bf3f526..00000000000
--- a/src/test/ui/const-generics/wf-misc.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/wf-misc.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: constant expression depends on a generic parameter
-  --> $DIR/wf-misc.rs:5:12
-   |
-LL |     let _: [u8; N + 1];
-   |            ^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: constant expression depends on a generic parameter
-  --> $DIR/wf-misc.rs:12:12
-   |
-LL |     let _: Const::<{N + 1}>;
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
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/error-codes/E0424.rs b/src/test/ui/error-codes/E0424.rs
index 3c6a1d4f88f..fa0c86ecf48 100644
--- a/src/test/ui/error-codes/E0424.rs
+++ b/src/test/ui/error-codes/E0424.rs
@@ -6,6 +6,10 @@ impl Foo {
     fn foo() {
         self.bar(); //~ ERROR E0424
     }
+
+    fn baz(_: i32) {
+        self.bar(); //~ ERROR E0424
+    }
 }
 
 fn main () {
diff --git a/src/test/ui/error-codes/E0424.stderr b/src/test/ui/error-codes/E0424.stderr
index 690a101496d..9b8a29e8272 100644
--- a/src/test/ui/error-codes/E0424.stderr
+++ b/src/test/ui/error-codes/E0424.stderr
@@ -1,21 +1,37 @@
 error[E0424]: expected value, found module `self`
   --> $DIR/E0424.rs:7:9
    |
-LL | /     fn foo() {
-LL | |         self.bar();
-   | |         ^^^^ `self` value is a keyword only available in methods with a `self` parameter
-LL | |     }
-   | |_____- this function doesn't have a `self` parameter
+LL |     fn foo() {
+   |        --- this function doesn't have a `self` parameter
+LL |         self.bar();
+   |         ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+   |
+help: add a `self` receiver parameter to make the associated `fn` a method
+   |
+LL |     fn foo(&self) {
+   |            ^^^^^
+
+error[E0424]: expected value, found module `self`
+  --> $DIR/E0424.rs:11:9
+   |
+LL |     fn baz(_: i32) {
+   |        --- this function doesn't have a `self` parameter
+LL |         self.bar();
+   |         ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+   |
+help: add a `self` receiver parameter to make the associated `fn` a method
+   |
+LL |     fn baz(&self, _: i32) {
+   |            ^^^^^^
 
 error[E0424]: expected unit struct, unit variant or constant, found module `self`
-  --> $DIR/E0424.rs:12:9
+  --> $DIR/E0424.rs:16:9
    |
-LL | / fn main () {
-LL | |     let self = "self";
-   | |         ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
-LL | | }
-   | |_- this function doesn't have a `self` parameter
+LL | fn main () {
+   |    ---- this function can't have a `self` parameter
+LL |     let self = "self";
+   |         ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0424`.
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-5099.rs b/src/test/ui/issues/issue-5099.rs
index d00fff32809..ee134835c37 100644
--- a/src/test/ui/issues/issue-5099.rs
+++ b/src/test/ui/issues/issue-5099.rs
@@ -1,3 +1,10 @@
-trait B < A > { fn a() -> A { this.a } } //~ ERROR cannot find value `this` in this scope
+trait B <A> {
+    fn a() -> A {
+        this.a //~ ERROR cannot find value `this` in this scope
+    }
+    fn b(x: i32) {
+        this.b(x); //~ ERROR cannot find value `this` in this scope
+    }
+}
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-5099.stderr b/src/test/ui/issues/issue-5099.stderr
index cc11db9c5ec..b52fd28b2b5 100644
--- a/src/test/ui/issues/issue-5099.stderr
+++ b/src/test/ui/issues/issue-5099.stderr
@@ -1,9 +1,33 @@
 error[E0425]: cannot find value `this` in this scope
-  --> $DIR/issue-5099.rs:1:31
+  --> $DIR/issue-5099.rs:3:9
    |
-LL | trait B < A > { fn a() -> A { this.a } }
-   |                               ^^^^ not found in this scope
+LL |         this.a
+   |         ^^^^ not found in this scope
+   |
+help: you might have meant to use `self` here instead
+   |
+LL |         self.a
+   |         ^^^^
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+   |
+LL |     fn a(&self) -> A {
+   |          ^^^^^
+
+error[E0425]: cannot find value `this` in this scope
+  --> $DIR/issue-5099.rs:6:9
+   |
+LL |         this.b(x);
+   |         ^^^^ not found in this scope
+   |
+help: you might have meant to use `self` here instead
+   |
+LL |         self.b(x);
+   |         ^^^^
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+   |
+LL |     fn b(&self, x: i32) {
+   |          ^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/issues/issue-59508-1.stderr b/src/test/ui/issues/issue-59508-1.stderr
index 85db20b13fb..5e97339f148 100644
--- a/src/test/ui/issues/issue-59508-1.stderr
+++ b/src/test/ui/issues/issue-59508-1.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
   --> $DIR/issue-59508-1.rs:12:25
    |
 LL |     pub fn do_things<T, 'a, 'b: 'a>() {
-   |                     ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
+   |                     ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
 
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-59508-1.rs:2:12
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/issues/issue-75307.rs b/src/test/ui/issues/issue-75307.rs
new file mode 100644
index 00000000000..2fe112a3b95
--- /dev/null
+++ b/src/test/ui/issues/issue-75307.rs
@@ -0,0 +1,3 @@
+fn main() {
+    format!(r"{}{}{}", named_arg=1); //~ ERROR invalid reference to positional arguments 1 and 2
+}
diff --git a/src/test/ui/issues/issue-75307.stderr b/src/test/ui/issues/issue-75307.stderr
new file mode 100644
index 00000000000..4a5d997e00d
--- /dev/null
+++ b/src/test/ui/issues/issue-75307.stderr
@@ -0,0 +1,10 @@
+error: invalid reference to positional arguments 1 and 2 (there is 1 argument)
+  --> $DIR/issue-75307.rs:2:13
+   |
+LL |     format!(r"{}{}{}", named_arg=1);
+   |             ^^^^^^^^^
+   |
+   = note: positional arguments are zero-based
+
+error: aborting due to previous error
+
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/mir/issue-75419-validation-impl-trait.rs b/src/test/ui/mir/issue-75419-validation-impl-trait.rs
new file mode 100644
index 00000000000..a8741befb0c
--- /dev/null
+++ b/src/test/ui/mir/issue-75419-validation-impl-trait.rs
@@ -0,0 +1,13 @@
+// build-pass
+
+// This used to fail MIR validation due to the types on both sides of
+// an assignment not being equal.
+// The failure doesn't occur with a check-only build.
+
+fn iter_slice<'a, T>(xs: &'a [T]) -> impl Iterator<Item = &'a T> {
+    xs.iter()
+}
+
+fn main() {
+    iter_slice::<()> as fn(_) -> _;
+}
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/expr-as-stmt-2.rs b/src/test/ui/parser/expr-as-stmt-2.rs
new file mode 100644
index 00000000000..3a18bdc3b73
--- /dev/null
+++ b/src/test/ui/parser/expr-as-stmt-2.rs
@@ -0,0 +1,10 @@
+// This is not autofixable because we give extra suggestions to end the first expression with `;`.
+fn foo(a: Option<u32>, b: Option<u32>) -> bool {
+    if let Some(x) = a { true } else { false }
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    && //~ ERROR mismatched types
+    if let Some(y) = a { true } else { false }
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/expr-as-stmt-2.stderr b/src/test/ui/parser/expr-as-stmt-2.stderr
new file mode 100644
index 00000000000..ee07c367633
--- /dev/null
+++ b/src/test/ui/parser/expr-as-stmt-2.stderr
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:3:26
+   |
+LL |     if let Some(x) = a { true } else { false }
+   |     ---------------------^^^^------------------ help: consider using a semicolon here
+   |     |                    |
+   |     |                    expected `()`, found `bool`
+   |     expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:3:40
+   |
+LL |     if let Some(x) = a { true } else { false }
+   |     -----------------------------------^^^^^--- help: consider using a semicolon here
+   |     |                                  |
+   |     |                                  expected `()`, found `bool`
+   |     expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:6:5
+   |
+LL |   fn foo(a: Option<u32>, b: Option<u32>) -> bool {
+   |                                             ---- expected `bool` because of return type
+LL |       if let Some(x) = a { true } else { false }
+   |       ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
+...
+LL | /     &&
+LL | |     if let Some(y) = a { true } else { false }
+   | |______________________________________________^ expected `bool`, found `&&bool`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/expr-as-stmt.fixed b/src/test/ui/parser/expr-as-stmt.fixed
index 1ce6f9c2503..02816ef2791 100644
--- a/src/test/ui/parser/expr-as-stmt.fixed
+++ b/src/test/ui/parser/expr-as-stmt.fixed
@@ -25,12 +25,6 @@ fn baz() -> i32 {
     //~^ ERROR mismatched types
 }
 
-fn qux(a: Option<u32>, b: Option<u32>) -> bool {
-    (if let Some(x) = a { true } else { false })
-    && //~ ERROR expected expression
-    if let Some(y) = a { true } else { false }
-}
-
 fn moo(x: u32) -> bool {
     (match x {
         _ => 1,
diff --git a/src/test/ui/parser/expr-as-stmt.rs b/src/test/ui/parser/expr-as-stmt.rs
index b526c17488e..93baa8278f8 100644
--- a/src/test/ui/parser/expr-as-stmt.rs
+++ b/src/test/ui/parser/expr-as-stmt.rs
@@ -25,12 +25,6 @@ fn baz() -> i32 {
     //~^ ERROR mismatched types
 }
 
-fn qux(a: Option<u32>, b: Option<u32>) -> bool {
-    if let Some(x) = a { true } else { false }
-    && //~ ERROR expected expression
-    if let Some(y) = a { true } else { false }
-}
-
 fn moo(x: u32) -> bool {
     match x {
         _ => 1,
diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr
index 4d93e130901..324aed0ad7c 100644
--- a/src/test/ui/parser/expr-as-stmt.stderr
+++ b/src/test/ui/parser/expr-as-stmt.stderr
@@ -22,16 +22,8 @@ LL |     { 42 } + foo;
    |     |
    |     help: parentheses are required to parse this as an expression: `({ 42 })`
 
-error: expected expression, found `&&`
-  --> $DIR/expr-as-stmt.rs:30:5
-   |
-LL |     if let Some(x) = a { true } else { false }
-   |     ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
-LL |     &&
-   |     ^^ expected expression
-
 error: expected expression, found `>`
-  --> $DIR/expr-as-stmt.rs:37:7
+  --> $DIR/expr-as-stmt.rs:31:7
    |
 LL |     } > 0
    |       ^ expected expression
@@ -75,7 +67,7 @@ LL |     { 3 } * 3
    |     |
    |     help: parentheses are required to parse this as an expression: `({ 3 })`
 
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0308, E0614.
 For more information about an error, try `rustc --explain E0308`.
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-2356.stderr b/src/test/ui/resolve/issue-2356.stderr
index b687f0b0af0..0339daa0d6a 100644
--- a/src/test/ui/resolve/issue-2356.stderr
+++ b/src/test/ui/resolve/issue-2356.stderr
@@ -70,14 +70,15 @@ LL |         purr();
 error[E0424]: expected value, found module `self`
   --> $DIR/issue-2356.rs:65:8
    |
-LL | /   fn meow() {
-LL | |     if self.whiskers > 3 {
-   | |        ^^^^ `self` value is a keyword only available in methods with a `self` parameter
-LL | |
-LL | |         println!("MEOW");
-LL | |     }
-LL | |   }
-   | |___- this function doesn't have a `self` parameter
+LL |   fn meow() {
+   |      ---- this function doesn't have a `self` parameter
+LL |     if self.whiskers > 3 {
+   |        ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+   |
+help: add a `self` receiver parameter to make the associated `fn` a method
+   |
+LL |   fn meow(&self) {
+   |           ^^^^^
 
 error[E0425]: cannot find function `grow_older` in this scope
   --> $DIR/issue-2356.rs:72:5
@@ -112,12 +113,10 @@ LL |     purr_louder();
 error[E0424]: expected value, found module `self`
   --> $DIR/issue-2356.rs:92:5
    |
-LL | / fn main() {
-LL | |     self += 1;
-   | |     ^^^^ `self` value is a keyword only available in methods with a `self` parameter
-LL | |
-LL | | }
-   | |_- this function doesn't have a `self` parameter
+LL | fn main() {
+   |    ---- this function can't have a `self` parameter
+LL |     self += 1;
+   |     ^^^^ `self` value is a keyword only available in methods with a `self` parameter
 
 error: aborting due to 17 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-lifetime-specifier.rs b/src/test/ui/suggestions/missing-lifetime-specifier.rs
index b09c1879d70..fe88d105c78 100644
--- a/src/test/ui/suggestions/missing-lifetime-specifier.rs
+++ b/src/test/ui/suggestions/missing-lifetime-specifier.rs
@@ -25,8 +25,6 @@ thread_local! {
     //~| ERROR missing lifetime specifier
     //~| ERROR missing lifetime specifier
     //~| ERROR missing lifetime specifier
-    //~| ERROR the lifetime bound for this object type cannot be deduced from context
-    //~| ERROR the lifetime bound for this object type cannot be deduced from context
 }
 thread_local! {
     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
@@ -39,8 +37,6 @@ thread_local! {
     //~| ERROR missing lifetime specifier
     //~| ERROR missing lifetime specifier
     //~| ERROR missing lifetime specifier
-    //~| ERROR the lifetime bound for this object type cannot be deduced from context
-    //~| ERROR the lifetime bound for this object type cannot be deduced from context
 }
 
 thread_local! {
@@ -52,9 +48,7 @@ thread_local! {
 }
 thread_local! {
     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR the lifetime bound for this object type cannot be deduced from context
-    //~| ERROR the lifetime bound for this object type cannot be deduced from context
-    //~| ERROR wrong number of lifetime arguments: expected 2, found 1
+    //~^ ERROR wrong number of lifetime arguments: expected 2, found 1
     //~| ERROR wrong number of lifetime arguments: expected 2, found 1
     //~| ERROR wrong number of lifetime arguments: expected 2, found 1
     //~| ERROR wrong number of lifetime arguments: expected 2, found 1
diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
index 2630cf1affa..9838ac72ad7 100644
--- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
@@ -71,7 +71,7 @@ LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar<'static, 'static>>>>> = Ref
    |                                             ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:32:48
+  --> $DIR/missing-lifetime-specifier.rs:30:48
    |
 LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
    |                                                ^ expected 2 lifetime parameters
@@ -83,7 +83,7 @@ LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                ^^^^^^^^^^^^^^^^^
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:32:48
+  --> $DIR/missing-lifetime-specifier.rs:30:48
    |
 LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
    |                                                ^ expected 2 lifetime parameters
@@ -95,7 +95,7 @@ LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                ^^^^^^^^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:37:44
+  --> $DIR/missing-lifetime-specifier.rs:35:44
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^ expected named lifetime parameter
@@ -107,7 +107,7 @@ LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<i32>>>>> = RefCell:
    |                                            ^^^^^^^^
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:37:49
+  --> $DIR/missing-lifetime-specifier.rs:35:49
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
    |                                                 ^ expected 2 lifetime parameters
@@ -119,7 +119,7 @@ LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>>
    |                                                 ^^^^^^^^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:37:44
+  --> $DIR/missing-lifetime-specifier.rs:35:44
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^ expected named lifetime parameter
@@ -131,7 +131,7 @@ LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<i32>>>>> = RefCell:
    |                                            ^^^^^^^^
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:37:49
+  --> $DIR/missing-lifetime-specifier.rs:35:49
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
    |                                                 ^ expected 2 lifetime parameters
@@ -143,7 +143,7 @@ LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>>
    |                                                 ^^^^^^^^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:54:44
+  --> $DIR/missing-lifetime-specifier.rs:50:44
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^ expected named lifetime parameter
@@ -155,7 +155,7 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> =
    |                                            ^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:54:44
+  --> $DIR/missing-lifetime-specifier.rs:50:44
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^ expected named lifetime parameter
@@ -166,91 +166,55 @@ help: consider using the `'static` lifetime
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^^^^^^
 
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/missing-lifetime-specifier.rs:23:45
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^
-
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/missing-lifetime-specifier.rs:23:45
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^
-
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/missing-lifetime-specifier.rs:37:45
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^^^^^^
-
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/missing-lifetime-specifier.rs:37:45
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^^^^^^
-
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:47:44
+  --> $DIR/missing-lifetime-specifier.rs:43:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:47:44
+  --> $DIR/missing-lifetime-specifier.rs:43:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:47:44
+  --> $DIR/missing-lifetime-specifier.rs:43:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:47:44
+  --> $DIR/missing-lifetime-specifier.rs:43:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:54:45
+  --> $DIR/missing-lifetime-specifier.rs:50:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:54:45
+  --> $DIR/missing-lifetime-specifier.rs:50:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/missing-lifetime-specifier.rs:54:45
-   |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^^^^^^^^^^^^^^^
-
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:54:45
+  --> $DIR/missing-lifetime-specifier.rs:50:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/missing-lifetime-specifier.rs:54:45
-   |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^^^^^^^^^^^^^^^
-
 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
-  --> $DIR/missing-lifetime-specifier.rs:54:45
+  --> $DIR/missing-lifetime-specifier.rs:50:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
 
-error: aborting due to 28 previous errors
+error: aborting due to 22 previous errors
 
-Some errors have detailed explanations: E0106, E0107, E0228.
+Some errors have detailed explanations: E0106, E0107.
 For more information about an 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/unknown-llvm-arg.rs b/src/test/ui/unknown-llvm-arg.rs
new file mode 100644
index 00000000000..289bae24f81
--- /dev/null
+++ b/src/test/ui/unknown-llvm-arg.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Cllvm-args=-not-a-real-llvm-arg
+// normalize-stderr-test "--help" -> "-help"
+// normalize-stderr-test "\n(\n|.)*" -> ""
+
+// I'm seeing "--help" locally, but "-help" in CI, so I'm normalizing it to just "-help".
+
+// Note that the rustc-supplied "program name", given when invoking LLVM, is used by LLVM to
+// generate user-facing error messages and a usage (--help) messages. If the program name is
+// `rustc`, the usage message in response to `--llvm-args="--help"` starts with:
+// ```
+//   USAGE: rustc [options]
+// ```
+// followed by the list of options not to `rustc` but to `llvm`.
+//
+// On the other hand, if the program name is set to `rustc -Cllvm-args="..." with`, the usage
+// message is more clear:
+// ```
+//   USAGE: rustc -Cllvm-args="..." with [options]
+// ```
+// This test captures the effect of the current program name setting on LLVM command line
+// error messages.
+fn main() {}
diff --git a/src/test/ui/unknown-llvm-arg.stderr b/src/test/ui/unknown-llvm-arg.stderr
new file mode 100644
index 00000000000..e1d3cfea28f
--- /dev/null
+++ b/src/test/ui/unknown-llvm-arg.stderr
@@ -0,0 +1 @@
+rustc -Cllvm-args="..." with: Unknown command line argument '-not-a-real-llvm-arg'.  Try: 'rustc -Cllvm-args="..." with -help'
\ No newline at end of file
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/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 5dede95a858..0a71361c992 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -447,6 +447,7 @@ impl Builder {
         let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets);
         package("rustc", HOSTS);
         package("rustc-dev", HOSTS);
+        package("rustc-docs", HOSTS);
         package("cargo", HOSTS);
         package("rust-mingw", MINGW);
         package("rust-std", TARGETS);
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 1653f354644834073d6d2541e27fae94588e685
+Subproject ab32ee88dade1b50c77347599e82ca2de3fb8a5
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/miri b/src/tools/miri
-Subproject cf633d0e897c065381b7b7d14984830176caf8b
+Subproject 1bfb26d6cae6f535ac1034877635fc0cef87fe6
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
diff --git a/src/tools/tier-check/Cargo.toml b/src/tools/tier-check/Cargo.toml
new file mode 100644
index 00000000000..9917b383aab
--- /dev/null
+++ b/src/tools/tier-check/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "tier-check"
+version = "0.1.0"
+authors = ["Eric Huss"]
+edition = "2018"
+license = "MIT OR Apache-2.0"
+
+[dependencies]
diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs
new file mode 100644
index 00000000000..b8d60a5e2fe
--- /dev/null
+++ b/src/tools/tier-check/src/main.rs
@@ -0,0 +1,52 @@
+//! This is a script for validating the platform support page in the rustc book.
+//!
+//! The script takes two arguments, the path to the Platform Support source
+//! page, and the second argument is the path to `rustc`.
+
+use std::collections::HashSet;
+
+fn main() {
+    let mut args = std::env::args().skip(1);
+    let src = args.next().expect("expected source file as first argument");
+    let filename = std::path::Path::new(&src).file_name().unwrap().to_str().unwrap();
+    let rustc = args.next().expect("expected rustc as second argument");
+    let output = std::process::Command::new(rustc)
+        .arg("--print=target-list")
+        .output()
+        .expect("rustc should run");
+    if !output.status.success() {
+        eprintln!("rustc failed to run");
+        std::process::exit(0);
+    }
+    let stdout = std::str::from_utf8(&output.stdout).expect("utf8");
+    let target_list: HashSet<_> = stdout.lines().collect();
+
+    let doc_targets_md = std::fs::read_to_string(&src).expect("failed to read input source");
+    let doc_targets: HashSet<_> = doc_targets_md
+        .lines()
+        .filter(|line| line.starts_with('`') && line.contains('|'))
+        // These platforms only exist on macos.
+        .filter(|line| !line.contains("[^apple]") || cfg!(target_os = "macos"))
+        .map(|line| line.split('`').skip(1).next().expect("expected target code span"))
+        .collect();
+
+    let missing: Vec<_> = target_list.difference(&doc_targets).collect();
+    let extra: Vec<_> = doc_targets.difference(&target_list).collect();
+    for target in &missing {
+        eprintln!(
+            "error: target `{}` is missing from {}\n\
+            If this is a new target, please add it to {}.",
+            target, filename, src
+        );
+    }
+    for target in &extra {
+        eprintln!(
+            "error: target `{}` is in {}, but does not appear in the rustc target list\n\
+            If the target has been removed, please edit {} and remove the target.",
+            target, filename, src
+        );
+    }
+    if !missing.is_empty() || !extra.is_empty() {
+        std::process::exit(1);
+    }
+}