about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorcsmoe <csmoe@msn.com>2020-05-18 08:46:24 +0800
committercsmoe <csmoe@msn.com>2020-05-19 11:02:29 +0800
commit2f311b07c8d95b1192e585e983535de89bcbdfaa (patch)
tree0e12c995dfdd9352eaa61d542c6f604aca23b456 /src
parent8841ede3648b5f12284dae850ec065374fd3af46 (diff)
parentd79f1bd31a1401b5d08096fcdf9a9eb23ddf95df (diff)
downloadrust-2f311b07c8d95b1192e585e983535de89bcbdfaa.tar.gz
rust-2f311b07c8d95b1192e585e983535de89bcbdfaa.zip
Merge branch 'master' into issue-69276
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/bootstrap.py9
-rw-r--r--src/bootstrap/builder.rs10
-rw-r--r--src/bootstrap/config.rs9
-rwxr-xr-xsrc/bootstrap/configure.py1
-rw-r--r--src/bootstrap/dist.rs121
-rw-r--r--src/bootstrap/flags.rs14
-rw-r--r--src/bootstrap/format.rs2
-rw-r--r--src/bootstrap/lib.rs8
-rw-r--r--src/bootstrap/native.rs16
-rw-r--r--src/bootstrap/sanity.rs8
-rw-r--r--src/bootstrap/test.rs12
-rwxr-xr-xsrc/ci/docker/run.sh10
-rw-r--r--src/ci/github-actions/ci.yml2
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc/src/codegen-options/index.md10
-rw-r--r--src/liballoc/alloc/tests.rs2
-rw-r--r--src/liballoc/collections/btree/map.rs53
-rw-r--r--src/liballoc/collections/linked_list/tests.rs1
-rw-r--r--src/liballoc/collections/vec_deque.rs20
-rw-r--r--src/liballoc/collections/vec_deque/tests.rs8
-rw-r--r--src/liballoc/lib.rs2
-rw-r--r--src/liballoc/raw_vec.rs224
-rw-r--r--src/liballoc/rc.rs50
-rw-r--r--src/liballoc/sync.rs53
-rw-r--r--src/liballoc/sync/tests.rs8
-rw-r--r--src/liballoc/vec.rs21
-rw-r--r--src/libarena/lib.rs39
-rw-r--r--src/libcore/any.rs16
-rw-r--r--src/libcore/cell.rs5
-rw-r--r--src/libcore/intrinsics.rs2
-rw-r--r--src/libcore/iter/range.rs582
-rw-r--r--src/libcore/iter/traits/iterator.rs2
-rw-r--r--src/libcore/iter/traits/marker.rs2
-rw-r--r--src/libcore/marker.rs7
-rw-r--r--src/libcore/mem/manually_drop.rs45
-rw-r--r--src/libcore/num/f32.rs2
-rw-r--r--src/libcore/num/f64.rs2
-rw-r--r--src/libcore/num/mod.rs118
-rw-r--r--src/libcore/option.rs45
-rw-r--r--src/libcore/panicking.rs18
-rw-r--r--src/libcore/ptr/mod.rs8
-rw-r--r--src/libcore/slice/mod.rs122
-rw-r--r--src/libcore/tests/iter.rs121
-rw-r--r--src/libcore/tests/lib.rs1
-rw-r--r--src/libpanic_unwind/seh.rs5
-rw-r--r--src/libproc_macro/bridge/client.rs10
-rw-r--r--src/libproc_macro/bridge/mod.rs5
-rw-r--r--src/libproc_macro/lib.rs8
-rw-r--r--src/librustc_ast/util/literal.rs75
-rw-r--r--src/librustc_ast_lowering/lib.rs2
-rw-r--r--src/librustc_ast_passes/ast_validation.rs39
-rw-r--r--src/librustc_ast_passes/node_count.rs2
-rw-r--r--src/librustc_attr/builtin.rs2
-rw-r--r--src/librustc_codegen_llvm/back/write.rs5
-rw-r--r--src/librustc_codegen_llvm/builder.rs10
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs1
-rw-r--r--src/librustc_codegen_ssa/back/link.rs27
-rw-r--r--src/librustc_codegen_ssa/back/write.rs16
-rw-r--r--src/librustc_codegen_ssa/debuginfo/type_names.rs1
-rw-r--r--src/librustc_data_structures/Cargo.toml2
-rw-r--r--src/librustc_data_structures/lib.rs2
-rw-r--r--src/librustc_data_structures/tiny_list.rs4
-rw-r--r--src/librustc_driver/lib.rs23
-rw-r--r--src/librustc_error_codes/error_codes.rs3
-rw-r--r--src/librustc_error_codes/error_codes/E0228.md40
-rw-r--r--src/librustc_error_codes/error_codes/E0307.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0571.md6
-rw-r--r--src/librustc_error_codes/error_codes/E0579.md10
-rw-r--r--src/librustc_error_codes/error_codes/E0581.md9
-rw-r--r--src/librustc_error_codes/error_codes/E0582.md4
-rw-r--r--src/librustc_error_codes/error_codes/E0589.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0754.md33
-rw-r--r--src/librustc_error_codes/error_codes/E0755.md2
-rw-r--r--src/librustc_expand/parse/lexer/tests.rs4
-rw-r--r--src/librustc_expand/proc_macro_server.rs11
-rw-r--r--src/librustc_hir/lib.rs2
-rw-r--r--src/librustc_incremental/lib.rs2
-rw-r--r--src/librustc_incremental/persist/load.rs2
-rw-r--r--src/librustc_incremental/persist/mod.rs2
-rw-r--r--src/librustc_incremental/persist/save.rs8
-rw-r--r--src/librustc_incremental/persist/work_product.rs46
-rw-r--r--src/librustc_index/vec.rs32
-rw-r--r--src/librustc_infer/infer/canonical/canonicalizer.rs1
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs2
-rw-r--r--src/librustc_infer/infer/freshen.rs1
-rw-r--r--src/librustc_infer/infer/lexical_region_resolve/mod.rs20
-rw-r--r--src/librustc_infer/traits/util.rs5
-rw-r--r--src/librustc_interface/queries.rs2
-rw-r--r--src/librustc_lexer/src/lib.rs13
-rw-r--r--src/librustc_lexer/src/unescape.rs92
-rw-r--r--src/librustc_lexer/src/unescape/tests.rs10
-rw-r--r--src/librustc_lint/builtin.rs20
-rw-r--r--src/librustc_lint/types.rs1
-rw-r--r--src/librustc_lint/unused.rs24
-rw-r--r--src/librustc_metadata/lib.rs2
-rw-r--r--src/librustc_middle/dep_graph/mod.rs4
-rw-r--r--src/librustc_middle/hir/map/mod.rs6
-rw-r--r--src/librustc_middle/hir/mod.rs3
-rw-r--r--src/librustc_middle/lib.rs2
-rw-r--r--src/librustc_middle/middle/region.rs4
-rw-r--r--src/librustc_middle/mir/interpret/pointer.rs28
-rw-r--r--src/librustc_middle/mir/mono.rs3
-rw-r--r--src/librustc_middle/mir/visit.rs18
-rw-r--r--src/librustc_middle/query/mod.rs6
-rw-r--r--src/librustc_middle/traits/query.rs2
-rw-r--r--src/librustc_middle/ty/adjustment.rs7
-rw-r--r--src/librustc_middle/ty/context.rs1
-rw-r--r--src/librustc_middle/ty/error.rs2
-rw-r--r--src/librustc_middle/ty/fast_reject.rs1
-rw-r--r--src/librustc_middle/ty/flags.rs5
-rw-r--r--src/librustc_middle/ty/instance.rs4
-rw-r--r--src/librustc_middle/ty/layout.rs14
-rw-r--r--src/librustc_middle/ty/list.rs149
-rw-r--r--src/librustc_middle/ty/mod.rs155
-rw-r--r--src/librustc_middle/ty/outlives.rs2
-rw-r--r--src/librustc_middle/ty/print/mod.rs1
-rw-r--r--src/librustc_middle/ty/print/obsolete.rs1
-rw-r--r--src/librustc_middle/ty/print/pretty.rs7
-rw-r--r--src/librustc_middle/ty/query/keys.rs12
-rw-r--r--src/librustc_middle/ty/relate.rs5
-rw-r--r--src/librustc_middle/ty/structural_impls.rs7
-rw-r--r--src/librustc_middle/ty/sty.rs7
-rw-r--r--src/librustc_middle/ty/trait_def.rs5
-rw-r--r--src/librustc_middle/ty/util.rs4
-rw-r--r--src/librustc_middle/ty/walk.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll.rs8
-rw-r--r--src/librustc_mir/borrow_check/type_check/input_output.rs56
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs55
-rw-r--r--src/librustc_mir/const_eval/eval_queries.rs2
-rw-r--r--src/librustc_mir/const_eval/mod.rs2
-rw-r--r--src/librustc_mir/interpret/eval_context.rs3
-rw-r--r--src/librustc_mir/interpret/intern.rs330
-rw-r--r--src/librustc_mir/interpret/intrinsics/type_name.rs1
-rw-r--r--src/librustc_mir/interpret/validity.rs8
-rw-r--r--src/librustc_mir/lib.rs2
-rw-r--r--src/librustc_mir/monomorphize/collector.rs6
-rw-r--r--src/librustc_mir/monomorphize/mod.rs4
-rw-r--r--src/librustc_mir/shim.rs3
-rw-r--r--src/librustc_mir/transform/const_prop.rs135
-rw-r--r--src/librustc_mir/transform/copy_prop.rs7
-rw-r--r--src/librustc_mir/transform/generator.rs15
-rw-r--r--src/librustc_mir/transform/inline.rs6
-rw-r--r--src/librustc_mir/transform/mod.rs4
-rw-r--r--src/librustc_mir/transform/simplify_try.rs352
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs7
-rw-r--r--src/librustc_mir_build/build/scope.rs2
-rw-r--r--src/librustc_mir_build/hair/pattern/check_match.rs2
-rw-r--r--src/librustc_mir_build/hair/pattern/const_to_pat.rs6
-rw-r--r--src/librustc_parse/lexer/mod.rs159
-rw-r--r--src/librustc_parse/parser/diagnostics.rs2
-rw-r--r--src/librustc_passes/liveness.rs4
-rw-r--r--src/librustc_passes/region.rs2
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_query_system/dep_graph/dep_node.rs2
-rw-r--r--src/librustc_query_system/dep_graph/graph.rs4
-rw-r--r--src/librustc_query_system/dep_graph/mod.rs4
-rw-r--r--src/librustc_query_system/lib.rs2
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs70
-rw-r--r--src/librustc_session/options.rs16
-rw-r--r--src/librustc_session/session.rs12
-rw-r--r--src/librustc_span/lib.rs2
-rw-r--r--src/librustc_span/source_map.rs25
-rw-r--r--src/librustc_symbol_mangling/legacy.rs2
-rw-r--r--src/librustc_symbol_mangling/v0.rs1
-rw-r--r--src/librustc_target/spec/mipsel_sony_psp.rs43
-rw-r--r--src/librustc_target/spec/mipsel_sony_psp_linker_script.ld34
-rw-r--r--src/librustc_target/spec/mod.rs9
-rw-r--r--src/librustc_trait_selection/traits/chalk_fulfill.rs8
-rw-r--r--src/librustc_trait_selection/traits/coherence.rs7
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs33
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs178
-rw-r--r--src/librustc_trait_selection/traits/mod.rs42
-rw-r--r--src/librustc_trait_selection/traits/project.rs5
-rw-r--r--src/librustc_trait_selection/traits/query/dropck_outlives.rs2
-rw-r--r--src/librustc_trait_selection/traits/select.rs9
-rw-r--r--src/librustc_trait_selection/traits/structural_match.rs5
-rw-r--r--src/librustc_trait_selection/traits/wf.rs2
-rw-r--r--src/librustc_traits/chalk/db.rs72
-rw-r--r--src/librustc_traits/chalk/lowering.rs5
-rw-r--r--src/librustc_traits/dropck_outlives.rs2
-rw-r--r--src/librustc_ty/ty.rs2
-rw-r--r--src/librustc_typeck/check/cast.rs1
-rw-r--r--src/librustc_typeck/check/closure.rs6
-rw-r--r--src/librustc_typeck/check/demand.rs36
-rw-r--r--src/librustc_typeck/check/intrinsic.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs152
-rw-r--r--src/librustc_typeck/coherence/builtin.rs19
-rw-r--r--src/librustc_typeck/variance/constraints.rs6
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/librustdoc/clean/types.rs9
-rw-r--r--src/librustdoc/config.rs2
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/html/layout.rs1
-rw-r--r--src/librustdoc/html/markdown.rs14
-rw-r--r--src/librustdoc/html/render.rs53
-rw-r--r--src/librustdoc/html/render/cache.rs64
-rw-r--r--src/librustdoc/html/static/main.js136
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs66
-rw-r--r--src/librustdoc/test.rs3
-rw-r--r--src/libserialize/lib.rs2
-rw-r--r--src/libstd/collections/hash/map.rs10
-rw-r--r--src/libstd/collections/hash/set.rs10
-rw-r--r--src/libstd/ffi/os_str.rs10
-rw-r--r--src/libstd/panicking.rs20
-rw-r--r--src/libstd/path.rs4
-rw-r--r--src/libstd/sync/mpsc/shared.rs2
-rw-r--r--src/libstd/sync/mpsc/sync.rs2
-rw-r--r--src/libstd/thread/mod.rs6
-rw-r--r--src/libtest/cli.rs4
-rw-r--r--src/rustllvm/PassWrapper.cpp4
m---------src/stdarch0
-rw-r--r--src/test/codegen/target-feature-multiple.rs9
-rw-r--r--src/test/incremental/const-generics/issue-62536.rs2
-rw-r--r--src/test/incremental/const-generics/issue-64087.rs2
-rw-r--r--src/test/mir-opt/byte_slice/rustc.main.SimplifyCfg-elaborate-drops.after.mir4
-rw-r--r--src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir6
-rw-r--r--src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff6
-rw-r--r--src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir6
-rw-r--r--src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff6
-rw-r--r--src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir20
-rw-r--r--src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir24
-rw-r--r--src/test/mir-opt/const_allocation2/32bit/rustc.main.ConstProp.after.mir18
-rw-r--r--src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir18
-rw-r--r--src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir12
-rw-r--r--src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir12
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable.rs8
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff52
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate.rs8
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff66
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs9
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff58
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs14
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff62
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_no_prop.rs12
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff69
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs15
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff74
-rw-r--r--src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff12
-rw-r--r--src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff2
-rw-r--r--src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff2
-rw-r--r--src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff31
-rw-r--r--src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff31
-rw-r--r--src/test/mir-opt/simplify-arm.rs32
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff45
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff37
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff58
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff45
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff109
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff100
-rw-r--r--src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff53
-rw-r--r--src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir22
-rw-r--r--src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir19
-rw-r--r--src/test/mir-opt/simplify_try_if_let.rs40
-rw-r--r--src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff127
-rw-r--r--src/test/rustdoc-js-std/alias-2.js4
-rw-r--r--src/test/rustdoc-js/doc-alias.js263
-rw-r--r--src/test/rustdoc-js/doc-alias.rs79
-rw-r--r--src/test/rustdoc/intra-link-trait-impl.rs35
-rw-r--r--src/test/rustdoc/issue-32374.rs4
-rw-r--r--src/test/rustdoc/test-strikethrough.rs6
-rw-r--r--src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs1
-rw-r--r--src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr22
-rw-r--r--src/test/ui/array-slice-vec/match_arr_unknown_len.rs2
-rw-r--r--src/test/ui/array-slice-vec/match_arr_unknown_len.stderr5
-rw-r--r--src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr24
-rw-r--r--src/test/ui/associated-type-bounds/duplicate.rs2
-rw-r--r--src/test/ui/associated-type-bounds/duplicate.stderr3
-rw-r--r--src/test/ui/associated-type-bounds/dyn-lcsit.stderr3
-rw-r--r--src/test/ui/associated-type-bounds/lcsit.stderr3
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.fixed2
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.stderr8
-rw-r--r--src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed2
-rw-r--r--src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr10
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr10
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr10
-rw-r--r--src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed2
-rw-r--r--src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr10
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.fixed2
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.stderr6
-rw-r--r--src/test/ui/associated-types/defaults-suitability.stderr16
-rw-r--r--src/test/ui/associated-types/defaults-unsound-62211-1.stderr18
-rw-r--r--src/test/ui/associated-types/defaults-unsound-62211-2.stderr18
-rw-r--r--src/test/ui/associated-types/issue-63593.stderr4
-rw-r--r--src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs11
-rw-r--r--src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr21
-rw-r--r--src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr5
-rw-r--r--src/test/ui/async-await/issue-61076.rs32
-rw-r--r--src/test/ui/async-await/issue-61076.stderr27
-rw-r--r--src/test/ui/async-await/issue-61949-self-return-type.stderr2
-rw-r--r--src/test/ui/async-await/try-on-option-in-async.rs3
-rw-r--r--src/test/ui/async-await/try-on-option-in-async.stderr6
-rw-r--r--src/test/ui/binding/const-param.stderr3
-rw-r--r--src/test/ui/const-generics/apit-with-const-param.rs2
-rw-r--r--src/test/ui/const-generics/apit-with-const-param.stderr3
-rw-r--r--src/test/ui/const-generics/argument_order.rs2
-rw-r--r--src/test/ui/const-generics/argument_order.stderr3
-rw-r--r--src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr6
-rw-r--r--src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr4
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.rs2
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.stderr3
-rw-r--r--src/test/ui/const-generics/array-wrapper-struct-ctor.rs2
-rw-r--r--src/test/ui/const-generics/array-wrapper-struct-ctor.stderr3
-rw-r--r--src/test/ui/const-generics/broken-mir-1.rs2
-rw-r--r--src/test/ui/const-generics/broken-mir-1.stderr3
-rw-r--r--src/test/ui/const-generics/broken-mir-2.rs2
-rw-r--r--src/test/ui/const-generics/broken-mir-2.stderr9
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.rs2
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.stderr3
-rw-r--r--src/test/ui/const-generics/cannot-infer-type-for-const-param.rs2
-rw-r--r--src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr3
-rw-r--r--src/test/ui/const-generics/concrete-const-as-fn-arg.rs2
-rw-r--r--src/test/ui/const-generics/concrete-const-as-fn-arg.stderr3
-rw-r--r--src/test/ui/const-generics/concrete-const-impl-method.rs2
-rw-r--r--src/test/ui/const-generics/concrete-const-impl-method.stderr3
-rw-r--r--src/test/ui/const-generics/condition-in-trait-const-arg.rs2
-rw-r--r--src/test/ui/const-generics/condition-in-trait-const-arg.stderr3
-rw-r--r--src/test/ui/const-generics/const-arg-in-fn.rs2
-rw-r--r--src/test/ui/const-generics/const-arg-in-fn.stderr3
-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.stderr3
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.rs2
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.stderr3
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.rs2
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.stderr3
-rw-r--r--src/test/ui/const-generics/const-generic-array-wrapper.rs2
-rw-r--r--src/test/ui/const-generics/const-generic-array-wrapper.stderr3
-rw-r--r--src/test/ui/const-generics/const-generic-type_name.rs2
-rw-r--r--src/test/ui/const-generics/const-generic-type_name.stderr3
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.rs2
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.stderr3
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.rs2
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.stderr3
-rw-r--r--src/test/ui/const-generics/const-param-in-trait.rs2
-rw-r--r--src/test/ui/const-generics/const-param-in-trait.stderr3
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-type-param.rs2
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr3
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.rs2
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.stderr3
-rw-r--r--src/test/ui/const-generics/const-types.rs2
-rw-r--r--src/test/ui/const-generics/const-types.stderr3
-rw-r--r--src/test/ui/const-generics/derive-debug-array-wrapper.rs2
-rw-r--r--src/test/ui/const-generics/derive-debug-array-wrapper.stderr9
-rw-r--r--src/test/ui/const-generics/different_byref.rs2
-rw-r--r--src/test/ui/const-generics/different_byref.stderr3
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.rs2
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.stderr3
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.rs2
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.stderr3
-rw-r--r--src/test/ui/const-generics/fn-taking-const-generic-array.rs2
-rw-r--r--src/test/ui/const-generics/fn-taking-const-generic-array.stderr3
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.rs2
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.stderr3
-rw-r--r--src/test/ui/const-generics/foreign-item-const-parameter.rs2
-rw-r--r--src/test/ui/const-generics/foreign-item-const-parameter.stderr3
-rw-r--r--src/test/ui/const-generics/impl-const-generic-struct.rs2
-rw-r--r--src/test/ui/const-generics/impl-const-generic-struct.stderr3
-rw-r--r--src/test/ui/const-generics/incorrect-number-of-const-args.rs2
-rw-r--r--src/test/ui/const-generics/incorrect-number-of-const-args.stderr3
-rw-r--r--src/test/ui/const-generics/infer_arg_from_pat.rs2
-rw-r--r--src/test/ui/const-generics/infer_arg_from_pat.stderr3
-rw-r--r--src/test/ui/const-generics/infer_arr_len_from_pat.rs2
-rw-r--r--src/test/ui/const-generics/infer_arr_len_from_pat.stderr3
-rw-r--r--src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.rs2
-rw-r--r--src/test/ui/const-generics/integer-literal-generic-arg-in-where-clause.stderr3
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.rs2
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.stderr3
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs2
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-1.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-1.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-2.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-2.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-61336.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61336.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-61422.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61422.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-61432.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61432.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-62579-no-match.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62579-no-match.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-64519.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-64519.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-66906.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-66906.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-70125-1.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-70125-1.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-70125-2.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-70125-2.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue-70167.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-70167.stderr3
-rw-r--r--src/test/ui/const-generics/issues/issue70273-assoc-fn.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr3
-rw-r--r--src/test/ui/const-generics/mut-ref-const-param-array.rs2
-rw-r--r--src/test/ui/const-generics/mut-ref-const-param-array.stderr3
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.rs2
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.stderr3
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.rs2
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.stderr3
-rw-r--r--src/test/ui/const-generics/slice-const-param-mismatch.rs2
-rw-r--r--src/test/ui/const-generics/slice-const-param-mismatch.stderr3
-rw-r--r--src/test/ui/const-generics/slice-const-param.rs2
-rw-r--r--src/test/ui/const-generics/slice-const-param.stderr3
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.rs2
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.stderr3
-rw-r--r--src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs2
-rw-r--r--src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr3
-rw-r--r--src/test/ui/const-generics/type_of_anon_const.rs2
-rw-r--r--src/test/ui/const-generics/type_of_anon_const.stderr3
-rw-r--r--src/test/ui/const-generics/types-mismatch-const-args.rs2
-rw-r--r--src/test/ui/const-generics/types-mismatch-const-args.stderr3
-rw-r--r--src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs2
-rw-r--r--src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr3
-rw-r--r--src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs2
-rw-r--r--src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr3
-rw-r--r--src/test/ui/const-generics/unused-const-param.rs2
-rw-r--r--src/test/ui/const-generics/unused-const-param.stderr3
-rw-r--r--src/test/ui/const-generics/unused_braces.rs2
-rw-r--r--src/test/ui/const-generics/unused_braces.stderr3
-rw-r--r--src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr14
-rw-r--r--src/test/ui/consts/const-eval/ref_to_int_match.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.stderr10
-rw-r--r--src/test/ui/consts/const-eval/ub-ref.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.rs8
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.stderr8
-rw-r--r--src/test/ui/consts/dangling-alloc-id-ice.rs4
-rw-r--r--src/test/ui/consts/dangling-alloc-id-ice.stderr22
-rw-r--r--src/test/ui/consts/dangling_raw_ptr.rs2
-rw-r--r--src/test/ui/consts/dangling_raw_ptr.stderr6
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_const.rs25
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_const.stderr39
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_const2.rs16
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_const2.stderr29
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references.rs3
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references.stderr6
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references_err.rs37
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references_err.stderr40
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references_ice.rs29
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr25
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.rs29
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.stderr39
-rw-r--r--src/test/ui/consts/miri_unleashed/raw_mutable_const.rs10
-rw-r--r--src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr16
-rw-r--r--src/test/ui/consts/raw-ptr-const.rs10
-rw-r--r--src/test/ui/consts/raw-ptr-const.stderr8
-rw-r--r--src/test/ui/error-codes/E0730.rs2
-rw-r--r--src/test/ui/error-codes/E0730.stderr3
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr2
-rw-r--r--src/test/ui/generic-associated-types/gat-incomplete-warning.stderr3
-rw-r--r--src/test/ui/hygiene/generic_params.stderr3
-rw-r--r--src/test/ui/hygiene/issue-61574-const-parameters.stderr3
-rw-r--r--src/test/ui/if-attrs/let-chains-attr.stderr3
-rw-r--r--src/test/ui/impl-trait-in-bindings.rs2
-rw-r--r--src/test/ui/impl-trait-in-bindings.stderr3
-rw-r--r--src/test/ui/impl-trait/bindings-opaque.rs2
-rw-r--r--src/test/ui/impl-trait/bindings-opaque.stderr3
-rw-r--r--src/test/ui/impl-trait/bindings.rs2
-rw-r--r--src/test/ui/impl-trait/bindings.stderr3
-rw-r--r--src/test/ui/impl-trait/bound-normalization-fail.stderr3
-rw-r--r--src/test/ui/impl-trait/bound-normalization-pass.stderr3
-rw-r--r--src/test/ui/impl-trait/example-calendar.rs26
-rw-r--r--src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs2
-rw-r--r--src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr3
-rw-r--r--src/test/ui/issues/issue-20005.stderr2
-rw-r--r--src/test/ui/issues/issue-22872.stderr6
-rw-r--r--src/test/ui/issues/issue-27078.stderr8
-rw-r--r--src/test/ui/issues/issue-42312.stderr8
-rw-r--r--src/test/ui/issues/issue-59508-1.rs2
-rw-r--r--src/test/ui/issues/issue-59508-1.stderr3
-rw-r--r--src/test/ui/issues/issue-71036.rs17
-rw-r--r--src/test/ui/issues/issue-71036.stderr12
-rw-r--r--src/test/ui/lint/issue-71290-unused-paren-binop.rs23
-rw-r--r--src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr2
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr1
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr1
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr1
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr1
-rw-r--r--src/test/ui/optimization-fuel-0.rs3
-rw-r--r--src/test/ui/optimization-fuel-0.stderr5
-rw-r--r--src/test/ui/optimization-fuel-1.rs3
-rw-r--r--src/test/ui/optimization-fuel-1.stderr5
-rw-r--r--src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr3
-rw-r--r--src/test/ui/parser/issue-3036.stderr2
-rw-r--r--src/test/ui/parser/recover-missing-semi.stderr4
-rw-r--r--src/test/ui/proc-macro/debug/auxiliary/macro-dump-debug.rs15
-rw-r--r--src/test/ui/proc-macro/debug/dump-debug.rs40
-rw-r--r--src/test/ui/proc-macro/debug/dump-debug.stderr166
-rw-r--r--src/test/ui/process-termination/process-termination-blocking-io.rs19
-rw-r--r--src/test/ui/process-termination/process-termination-simple.rs13
-rw-r--r--src/test/ui/regions/issue-72051-member-region-hang.rs7
-rw-r--r--src/test/ui/resolve/issue-65035-static-with-parent-generics.rs2
-rw-r--r--src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr3
-rw-r--r--src/test/ui/rfc-2457/auxiliary/mod_file_nonascii_with_path_allowed-aux.rs1
-rw-r--r--src/test/ui/rfc-2457/mod_file_nonascii_forbidden.rs6
-rw-r--r--src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr20
-rw-r--r--src/test/ui/rfc-2457/mod_file_nonascii_with_path_allowed.rs7
-rw-r--r--src/test/ui/rfc-2457/mod_inline_nonascii_allowed.rs8
-rw-r--r--src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.rs6
-rw-r--r--src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.stderr9
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr7
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs2
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs2
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs2
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr3
-rw-r--r--src/test/ui/sanitize/issue-72154-lifetime-markers.rs31
-rw-r--r--src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.rs18
-rw-r--r--src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr18
-rw-r--r--src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr10
-rw-r--r--src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr24
-rw-r--r--src/test/ui/suggestions/missing-lifetime-specifier.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/assoc-type-const.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/assoc-type-const.stderr3
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr3
-rw-r--r--src/test/ui/type/type-params-in-different-spaces-2.stderr14
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed2
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr6
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr3
-rw-r--r--src/test/ui/unsized3.stderr4
-rw-r--r--src/test/ui/wf/wf-trait-associated-type-trait.stderr10
-rw-r--r--src/test/ui/wf/wf-trait-default-fn-arg.stderr9
-rw-r--r--src/test/ui/wf/wf-trait-default-fn-ret.stderr9
-rw-r--r--src/test/ui/wf/wf-trait-default-fn-where-clause.stderr9
-rw-r--r--src/test/ui/wf/wf-trait-fn-arg.stderr9
-rw-r--r--src/test/ui/wf/wf-trait-fn-ret.stderr9
-rw-r--r--src/test/ui/wf/wf-trait-fn-where-clause.stderr9
-rw-r--r--src/tools/build-manifest/src/main.rs18
-rw-r--r--src/tools/clippy/CHANGELOG.md2
-rw-r--r--src/tools/clippy/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs361
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs159
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs173
-rw-r--r--src/tools/clippy/clippy_lints/src/match_on_vec_items.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs4
-rw-r--r--src/tools/clippy/src/driver.rs4
-rw-r--r--src/tools/clippy/src/lintlist/mod.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/builtin-type-shadow.stderr2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs27
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr24
-rw-r--r--src/tools/clippy/tests/ui/future_not_send.rs1
-rw-r--r--src/tools/clippy/tests/ui/future_not_send.stderr6
-rw-r--r--src/tools/clippy/tests/ui/manual_async_fn.fixed67
-rw-r--r--src/tools/clippy/tests/ui/manual_async_fn.rs79
-rw-r--r--src/tools/clippy/tests/ui/manual_async_fn.stderr98
-rw-r--r--src/tools/clippy/tests/ui/manual_memcpy.rs15
-rw-r--r--src/tools/clippy/tests/ui/manual_memcpy.stderr20
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive.rs137
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive.stderr103
-rw-r--r--src/tools/clippy/tests/ui/match_on_vec_items.rs22
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed58
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs58
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr28
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed73
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs73
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr32
-rw-r--r--src/tools/compiletest/src/main.rs5
m---------src/tools/miri14
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustdoc-js/tester.js105
585 files changed, 7921 insertions, 3018 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 9a91f37c5de..b7d0fac5be3 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -180,13 +180,16 @@ def format_build_time(duration):
 def default_build_triple():
     """Build triple as in LLVM"""
     default_encoding = sys.getdefaultencoding()
-    required = not sys.platform == 'win32'
-    ostype = require(["uname", "-s"], exit=required).decode(default_encoding)
-    cputype = require(['uname', '-m'], exit=required).decode(default_encoding)
+    required = sys.platform != 'win32'
+    ostype = require(["uname", "-s"], exit=required)
+    cputype = require(['uname', '-m'], exit=required)
 
     if ostype is None or cputype is None:
         return 'x86_64-pc-windows-msvc'
 
+    ostype = ostype.decode(default_encoding)
+    cputype = cputype.decode(default_encoding)
+
     # The goal here is to come up with the same triple as LLVM would,
     # at least for the subset of platforms we're willing to target.
     ostype_mapper = {
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index b0e06731330..4bc81a7b42d 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -439,7 +439,6 @@ impl<'a> Builder<'a> {
                 dist::Clippy,
                 dist::Miri,
                 dist::LlvmTools,
-                dist::Lldb,
                 dist::Extended,
                 dist::HashSign
             ),
@@ -916,7 +915,14 @@ impl<'a> Builder<'a> {
             .env("RUSTC", self.out.join("bootstrap/debug/rustc"))
             .env("RUSTC_REAL", self.rustc(compiler))
             .env("RUSTC_STAGE", stage.to_string())
-            .env("RUSTC_DEBUG_ASSERTIONS", self.config.rust_debug_assertions.to_string())
+            .env(
+                "RUSTC_DEBUG_ASSERTIONS",
+                if mode == Mode::Std {
+                    self.config.rust_debug_assertions_std.to_string()
+                } else {
+                    self.config.rust_debug_assertions.to_string()
+                },
+            )
             .env("RUSTC_SYSROOT", &sysroot)
             .env("RUSTC_LIBDIR", &libdir)
             .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 390630ee51b..771f952abc0 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -85,7 +85,6 @@ pub struct Config {
 
     pub use_lld: bool,
     pub lld_enabled: bool,
-    pub lldb_enabled: bool,
     pub llvm_tools_enabled: bool,
 
     pub llvm_cflags: Option<String>,
@@ -98,6 +97,7 @@ pub struct Config {
     pub rust_codegen_units: Option<u32>,
     pub rust_codegen_units_std: Option<u32>,
     pub rust_debug_assertions: bool,
+    pub rust_debug_assertions_std: bool,
     pub rust_debuginfo_level_rustc: u32,
     pub rust_debuginfo_level_std: u32,
     pub rust_debuginfo_level_tools: u32,
@@ -315,6 +315,7 @@ struct Rust {
     codegen_units: Option<u32>,
     codegen_units_std: Option<u32>,
     debug_assertions: Option<bool>,
+    debug_assertions_std: Option<bool>,
     debuginfo_level: Option<u32>,
     debuginfo_level_rustc: Option<u32>,
     debuginfo_level_std: Option<u32>,
@@ -337,7 +338,6 @@ struct Rust {
     lld: Option<bool>,
     use_lld: Option<bool>,
     llvm_tools: Option<bool>,
-    lldb: Option<bool>,
     deny_warnings: Option<bool>,
     backtrace_on_ice: Option<bool>,
     verify_llvm_ir: Option<bool>,
@@ -520,6 +520,7 @@ impl Config {
         let mut llvm_assertions = None;
         let mut debug = None;
         let mut debug_assertions = None;
+        let mut debug_assertions_std = None;
         let mut debuginfo_level = None;
         let mut debuginfo_level_rustc = None;
         let mut debuginfo_level_std = None;
@@ -562,6 +563,7 @@ impl Config {
         if let Some(ref rust) = toml.rust {
             debug = rust.debug;
             debug_assertions = rust.debug_assertions;
+            debug_assertions_std = rust.debug_assertions_std;
             debuginfo_level = rust.debuginfo_level;
             debuginfo_level_rustc = rust.debuginfo_level_rustc;
             debuginfo_level_std = rust.debuginfo_level_std;
@@ -585,7 +587,6 @@ impl Config {
             }
             set(&mut config.use_lld, rust.use_lld);
             set(&mut config.lld_enabled, rust.lld);
-            set(&mut config.lldb_enabled, rust.lldb);
             set(&mut config.llvm_tools_enabled, rust.llvm_tools);
             config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
             config.rustc_default_linker = rust.default_linker.clone();
@@ -661,6 +662,8 @@ impl Config {
 
         let default = debug == Some(true);
         config.rust_debug_assertions = debug_assertions.unwrap_or(default);
+        config.rust_debug_assertions_std =
+            debug_assertions_std.unwrap_or(config.rust_debug_assertions);
 
         let with_defaults = |debuginfo_level_specific: Option<u32>| {
             debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 2a46c563d1f..d1e53db573e 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -57,7 +57,6 @@ o("cargo-native-static", "build.cargo-native-static", "static native libraries i
 o("profiler", "build.profiler", "build the profiler runtime")
 o("full-tools", None, "enable all tools")
 o("lld", "rust.lld", "build lld")
-o("lldb", "rust.lldb", "build lldb")
 o("missing-tools", "dist.missing-tools", "allow failures when building tools")
 o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++")
 o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard")
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index bae90411496..c4bca4a0040 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -38,8 +38,6 @@ pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
         format!("{}-{}", component, builder.rustfmt_package_vers())
     } else if component == "llvm-tools" {
         format!("{}-{}", component, builder.llvm_tools_package_vers())
-    } else if component == "lldb" {
-        format!("{}-{}", component, builder.lldb_package_vers())
     } else {
         assert!(component.starts_with("rust"));
         format!("{}-{}", component, builder.rust_package_vers())
@@ -1645,7 +1643,6 @@ impl Step for Extended {
         let llvm_tools_installer = builder.ensure(LlvmTools { target });
         let clippy_installer = builder.ensure(Clippy { compiler, target });
         let miri_installer = builder.ensure(Miri { compiler, target });
-        let lldb_installer = builder.ensure(Lldb { target });
         let mingw_installer = builder.ensure(Mingw { host: target });
         let analysis_installer = builder.ensure(Analysis { compiler, target });
 
@@ -1681,7 +1678,6 @@ impl Step for Extended {
         tarballs.extend(miri_installer.clone());
         tarballs.extend(rustfmt_installer.clone());
         tarballs.extend(llvm_tools_installer);
-        tarballs.extend(lldb_installer);
         tarballs.push(analysis_installer);
         tarballs.push(std_installer);
         if builder.config.docs {
@@ -2222,7 +2218,6 @@ impl Step for HashSign {
         cmd.arg(builder.package_vers(&builder.release_num("miri")));
         cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
         cmd.arg(builder.llvm_tools_package_vers());
-        cmd.arg(builder.lldb_package_vers());
 
         builder.create_dir(&distdir(builder));
 
@@ -2349,119 +2344,3 @@ impl Step for LlvmTools {
         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
     }
 }
-
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
-pub struct Lldb {
-    pub target: Interned<String>,
-}
-
-impl Step for Lldb {
-    type Output = Option<PathBuf>;
-    const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/llvm-project/lldb").path("src/tools/lldb")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(Lldb { target: run.target });
-    }
-
-    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
-        let target = self.target;
-
-        if builder.config.dry_run {
-            return None;
-        }
-
-        let bindir = builder.llvm_out(target).join("bin");
-        let lldb_exe = bindir.join(exe("lldb", &target));
-        if !lldb_exe.exists() {
-            return None;
-        }
-
-        builder.info(&format!("Dist Lldb ({})", target));
-        let src = builder.src.join("src/llvm-project/lldb");
-        let name = pkgname(builder, "lldb");
-
-        let tmp = tmpdir(builder);
-        let image = tmp.join("lldb-image");
-        drop(fs::remove_dir_all(&image));
-
-        // Prepare the image directory
-        let root = image.join("lib/rustlib").join(&*target);
-        let dst = root.join("bin");
-        t!(fs::create_dir_all(&dst));
-        for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] {
-            let exe = bindir.join(exe(program, &target));
-            builder.install(&exe, &dst, 0o755);
-        }
-
-        // The libraries.
-        let libdir = builder.llvm_out(target).join("lib");
-        let dst = root.join("lib");
-        t!(fs::create_dir_all(&dst));
-        for entry in t!(fs::read_dir(&libdir)) {
-            let entry = entry.unwrap();
-            if let Ok(name) = entry.file_name().into_string() {
-                if name.starts_with("liblldb.") && !name.ends_with(".a") {
-                    if t!(entry.file_type()).is_symlink() {
-                        builder.copy_to_folder(&entry.path(), &dst);
-                    } else {
-                        builder.install(&entry.path(), &dst, 0o755);
-                    }
-                }
-            }
-        }
-
-        // The lldb scripts might be installed in lib/python$version
-        // or in lib64/python$version.  If lib64 exists, use it;
-        // otherwise lib.
-        let libdir = builder.llvm_out(target).join("lib64");
-        let (libdir, libdir_name) = if libdir.exists() {
-            (libdir, "lib64")
-        } else {
-            (builder.llvm_out(target).join("lib"), "lib")
-        };
-        for entry in t!(fs::read_dir(&libdir)) {
-            let entry = t!(entry);
-            if let Ok(name) = entry.file_name().into_string() {
-                if name.starts_with("python") {
-                    let dst = root.join(libdir_name).join(entry.file_name());
-                    t!(fs::create_dir_all(&dst));
-                    builder.cp_r(&entry.path(), &dst);
-                    break;
-                }
-            }
-        }
-
-        // Prepare the overlay
-        let overlay = tmp.join("lldb-overlay");
-        drop(fs::remove_dir_all(&overlay));
-        builder.create_dir(&overlay);
-        builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
-        builder.create(&overlay.join("version"), &builder.lldb_vers());
-
-        // Generate the installer tarball
-        let mut cmd = rust_installer(builder);
-        cmd.arg("generate")
-            .arg("--product-name=Rust")
-            .arg("--rel-manifest-dir=rustlib")
-            .arg("--success-message=lldb-installed.")
-            .arg("--image-dir")
-            .arg(&image)
-            .arg("--work-dir")
-            .arg(&tmpdir(builder))
-            .arg("--output-dir")
-            .arg(&distdir(builder))
-            .arg("--non-installed-overlay")
-            .arg(&overlay)
-            .arg(format!("--package-name={}-{}", name, target))
-            .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--component-name=lldb-preview");
-
-        builder.run(&mut cmd);
-        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
-    }
-}
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index fb380af0a47..646b9e05d99 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -503,6 +503,20 @@ Arguments:
             }
         };
 
+        if let Subcommand::Check { .. } = &cmd {
+            if matches.opt_str("stage").is_some() {
+                println!("{}", "--stage not supported for x.py check, always treated as stage 0");
+                process::exit(1);
+            }
+            if matches.opt_str("keep-stage").is_some() {
+                println!(
+                    "{}",
+                    "--keep-stage not supported for x.py check, only one stage available"
+                );
+                process::exit(1);
+            }
+        }
+
         Flags {
             verbose: matches.opt_count("verbose"),
             stage: matches.opt_str("stage").map(|j| j.parse().expect("`stage` should be a number")),
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 6653c505bf5..390b7e96b9a 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -23,7 +23,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
     if !status.success() {
         eprintln!(
             "Running `{}` failed.\nIf you're running `tidy`, \
-            try again with `--bless` flag. Or, you just want to format \
+            try again with `--bless`. Or, if you just want to format \
             code, run `./x.py fmt` instead.",
             cmd_debug,
         );
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 31bbd92cd62..15bf831a148 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1029,14 +1029,6 @@ impl Build {
         self.rust_version()
     }
 
-    fn lldb_package_vers(&self) -> String {
-        self.package_vers(channel::CFG_RELEASE_NUM)
-    }
-
-    fn lldb_vers(&self) -> String {
-        self.rust_version()
-    }
-
     fn llvm_link_tools_dynamically(&self, target: Interned<String>) -> bool {
         target.contains("linux-gnu") || target.contains("apple-darwin")
     }
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index bcd79a49ece..446017f1fab 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -184,7 +184,7 @@ impl Step for Llvm {
         }
 
         // For distribution we want the LLVM tools to be *statically* linked to libstdc++
-        if builder.config.llvm_tools_enabled || builder.config.lldb_enabled {
+        if builder.config.llvm_tools_enabled {
             if !target.contains("msvc") {
                 if target.contains("apple") {
                     cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++");
@@ -212,17 +212,9 @@ impl Step for Llvm {
             enabled_llvm_projects.push("compiler-rt");
         }
 
-        if builder.config.lldb_enabled {
-            enabled_llvm_projects.push("clang");
-            enabled_llvm_projects.push("lldb");
-            // For the time being, disable code signing.
-            cfg.define("LLDB_CODESIGN_IDENTITY", "");
-            cfg.define("LLDB_NO_DEBUGSERVER", "ON");
-        } else {
-            // LLDB requires libxml2; but otherwise we want it to be disabled.
-            // See https://github.com/rust-lang/rust/pull/50104
-            cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
-        }
+        // We want libxml to be disabled.
+        // See https://github.com/rust-lang/rust/pull/50104
+        cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
 
         if !enabled_llvm_projects.is_empty() {
             enabled_llvm_projects.sort();
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 1760d655b3b..74b47d07728 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -117,14 +117,6 @@ pub fn check(build: &mut Build) {
                 build.config.ninja = true;
             }
         }
-
-        if build.config.lldb_enabled {
-            cmd_finder.must_have("swig");
-            let out = output(Command::new("swig").arg("-version"));
-            if !out.contains("SWIG Version 3") && !out.contains("SWIG Version 4") {
-                panic!("Ensure that Swig 3.x.x or 4.x.x is installed.");
-            }
-        }
     }
 
     build.config.python = build
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index ad3fd0d64a3..96196a80be4 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -436,7 +436,6 @@ impl Step for Miri {
 
             // miri tests need to know about the stage sysroot
             cargo.env("MIRI_SYSROOT", miri_sysroot);
-            cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
             cargo.env("MIRI_PATH", miri);
 
@@ -1097,20 +1096,15 @@ impl Step for Compiletest {
                     .to_string()
             })
         };
-        let lldb_exe = if builder.config.lldb_enabled {
-            // Test against the lldb that was just built.
-            builder.llvm_out(target).join("bin").join("lldb")
-        } else {
-            PathBuf::from("lldb")
-        };
-        let lldb_version = Command::new(&lldb_exe)
+        let lldb_exe = "lldb";
+        let lldb_version = Command::new(lldb_exe)
             .arg("--version")
             .output()
             .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
             .ok();
         if let Some(ref vers) = lldb_version {
             cmd.arg("--lldb-version").arg(vers);
-            let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
+            let lldb_python_dir = run(Command::new(lldb_exe).arg("-P")).ok();
             if let Some(ref dir) = lldb_python_dir {
                 cmd.arg("--lldb-python-dir").arg(dir);
             }
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index f29f9f3bf1c..d891ad1b668 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -17,6 +17,8 @@ dist=$objdir/build/dist
 
 source "$ci_dir/shared.sh"
 
+CACHE_DOMAIN="${CACHE_DOMAIN:-ci-caches.rust-lang.org}"
+
 if [ -f "$docker_dir/$image/Dockerfile" ]; then
     if [ "$CI" != "" ]; then
       hash_key=/tmp/.docker-hash-key.txt
@@ -38,9 +40,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       cksum=$(sha512sum $hash_key | \
         awk '{print $1}')
 
-      s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
-      url="https://$SCCACHE_BUCKET.s3.amazonaws.com/docker/$cksum"
-      upload="aws s3 cp - $s3url"
+      url="https://$CACHE_DOMAIN/docker/$cksum"
 
       echo "Attempting to download $url"
       rm -f /tmp/rustci_docker_cache
@@ -65,7 +65,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       -f "$dockerfile" \
       "$context"
 
-    if [ "$upload" != "" ]; then
+    if [ "$CI" != "" ]; then
+      s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
+      upload="aws s3 cp - $s3url"
       digest=$(docker inspect rust-ci --format '{{.Id}}')
       echo "Built container $digest"
       if ! grep -q "$digest" <(echo "$loaded_images"); then
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 647da7c8a7e..1c120f81634 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -37,6 +37,7 @@ x--expand-yaml-anchors--remove:
   - &public-variables
     SCCACHE_BUCKET: rust-lang-gha-caches
     TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate
+    CACHE_DOMAIN: ci-caches-gha.rust-lang.org
 
   - &prod-variables
     SCCACHE_BUCKET: rust-lang-gha-caches
@@ -51,6 +52,7 @@ x--expand-yaml-anchors--remove:
     # (caches, artifacts...).
     CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
     ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
+    CACHE_DOMAIN: ci-caches-gha.rust-lang.org
 
   - &base-job
     env: {}
diff --git a/src/doc/book b/src/doc/book
-Subproject e37c0e84e2ef73d3a4ebffda8011db6814a3b02
+Subproject 6247be15a7f7509559f7981ee2209b9e0cc121d
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 8204c1d123472cd17f0c1c5c77300ae802eb027
+Subproject 49270740c7a4bff2763e6bc730b191d45b7d516
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 40beccdf1bb8eb9184a2e3b42db8b8c6e394247
+Subproject 366c50a03bed928589771eba8a6f18e0c0c01d2
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 4d2d275997746d35eabfc4d992dfbdcce2f626e
+Subproject d1517d4e3f29264c5c67bce2658516bb5202c80
diff --git a/src/doc/reference b/src/doc/reference
-Subproject ed22e6fbfcb6ce436e9ea3b4bb4a55b2fb50a57
+Subproject 892b928b565e35d25b6f9c47faee03b94bc4148
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject ffc99581689fe2455908aaef5f5cf50dd03bb8f
+Subproject ab072b14393cbd9e8a1d1d75879bf51e27217bb
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index dbe281be7df..c638f88057a 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -464,7 +464,15 @@ machine. Each target has a default base CPU.
 
 Individual targets will support different features; this flag lets you control
 enabling or disabling a feature. Each feature should be prefixed with a `+` to
-enable it or `-` to disable it. Separate multiple features with commas.
+enable it or `-` to disable it.
+
+Features from multiple `-C target-feature` options are combined. \
+Multiple features can be specified in a single option by separating them
+with commas - `-C target-feature=+x,-y`. \
+If some feature is specified more than once with both `+` and `-`,
+then values passed later override values passed earlier. \
+For example, `-C target-feature=+x,-y,+z -Ctarget-feature=-x,+y`
+is equivalent to `-C target-feature=-x,+y,+z`.
 
 To see the valid options and an example of use, run `rustc --print
 target-features`.
diff --git a/src/liballoc/alloc/tests.rs b/src/liballoc/alloc/tests.rs
index 1ad40eca93b..1c003983df9 100644
--- a/src/liballoc/alloc/tests.rs
+++ b/src/liballoc/alloc/tests.rs
@@ -23,7 +23,7 @@ fn allocate_zeroed() {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn alloc_owned_small(b: &mut Bencher) {
     b.iter(|| {
         let _: Box<_> = box 10;
diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs
index 113df80d0c2..c6cb39b1bf5 100644
--- a/src/liballoc/collections/btree/map.rs
+++ b/src/liballoc/collections/btree/map.rs
@@ -215,59 +215,6 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
             clone_subtree(self.root.as_ref().unwrap().as_ref())
         }
     }
-
-    fn clone_from(&mut self, other: &Self) {
-        BTreeClone::clone_from(self, other);
-    }
-}
-
-trait BTreeClone {
-    fn clone_from(&mut self, other: &Self);
-}
-
-impl<K: Clone, V: Clone> BTreeClone for BTreeMap<K, V> {
-    default fn clone_from(&mut self, other: &Self) {
-        *self = other.clone();
-    }
-}
-
-impl<K: Clone + Ord, V: Clone> BTreeClone for BTreeMap<K, V> {
-    fn clone_from(&mut self, other: &Self) {
-        // This truncates `self` to `other.len()` by calling `split_off` on
-        // the first key after `other.len()` elements if it exists.
-        let split_off_key = if self.len() > other.len() {
-            let diff = self.len() - other.len();
-            if diff <= other.len() {
-                self.iter().nth_back(diff - 1).map(|pair| (*pair.0).clone())
-            } else {
-                self.iter().nth(other.len()).map(|pair| (*pair.0).clone())
-            }
-        } else {
-            None
-        };
-        if let Some(key) = split_off_key {
-            self.split_off(&key);
-        }
-
-        let mut siter = self.range_mut(..);
-        let mut oiter = other.iter();
-        // After truncation, `self` is at most as long as `other` so this loop
-        // replaces every key-value pair in `self`. Since `oiter` is in sorted
-        // order and the structure of the `BTreeMap` stays the same,
-        // the BTree invariants are maintained at the end of the loop.
-        while !siter.is_empty() {
-            if let Some((ok, ov)) = oiter.next() {
-                // SAFETY: This is safe because `siter` is nonempty.
-                let (sk, sv) = unsafe { siter.next_unchecked() };
-                sk.clone_from(ok);
-                sv.clone_from(ov);
-            } else {
-                break;
-            }
-        }
-        // If `other` is longer than `self`, the remaining elements are inserted.
-        self.extend(oiter.map(|(k, v)| ((*k).clone(), (*v).clone())));
-    }
 }
 
 impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs
index 085f734ed91..b8c93a28bba 100644
--- a/src/liballoc/collections/linked_list/tests.rs
+++ b/src/liballoc/collections/linked_list/tests.rs
@@ -182,7 +182,6 @@ fn test_insert_prev() {
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg_attr(miri, ignore)] // Miri does not support threads
 fn test_send() {
     let n = list_from(&[1, 2, 3]);
     thread::spawn(move || {
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 2f50234b6d5..540649c61b3 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -1354,7 +1354,9 @@ impl<T> VecDeque<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_front(&mut self, value: T) {
-        self.grow_if_necessary();
+        if self.is_full() {
+            self.grow();
+        }
 
         self.tail = self.wrap_sub(self.tail, 1);
         let tail = self.tail;
@@ -1377,7 +1379,9 @@ impl<T> VecDeque<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_back(&mut self, value: T) {
-        self.grow_if_necessary();
+        if self.is_full() {
+            self.grow();
+        }
 
         let head = self.head;
         self.head = self.wrap_add(self.head, 1);
@@ -1485,7 +1489,9 @@ impl<T> VecDeque<T> {
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
     pub fn insert(&mut self, index: usize, value: T) {
         assert!(index <= self.len(), "index out of bounds");
-        self.grow_if_necessary();
+        if self.is_full() {
+            self.grow();
+        }
 
         // Move the least number of elements in the ring buffer and insert
         // the given object
@@ -2003,11 +2009,13 @@ impl<T> VecDeque<T> {
     }
 
     // This may panic or abort
-    #[inline]
-    fn grow_if_necessary(&mut self) {
+    #[inline(never)]
+    fn grow(&mut self) {
         if self.is_full() {
             let old_cap = self.cap();
-            self.buf.double();
+            // Double the buffer size.
+            self.buf.reserve_exact(old_cap, old_cap);
+            assert!(self.cap() == old_cap * 2);
             unsafe {
                 self.handle_capacity_increase(old_cap);
             }
diff --git a/src/liballoc/collections/vec_deque/tests.rs b/src/liballoc/collections/vec_deque/tests.rs
index 0a3f3300323..fc2ec7908e8 100644
--- a/src/liballoc/collections/vec_deque/tests.rs
+++ b/src/liballoc/collections/vec_deque/tests.rs
@@ -3,7 +3,7 @@ use super::*;
 use test;
 
 #[bench]
-#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_push_back_100(b: &mut test::Bencher) {
     let mut deq = VecDeque::with_capacity(101);
     b.iter(|| {
@@ -16,7 +16,7 @@ fn bench_push_back_100(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_push_front_100(b: &mut test::Bencher) {
     let mut deq = VecDeque::with_capacity(101);
     b.iter(|| {
@@ -29,7 +29,7 @@ fn bench_push_front_100(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_pop_back_100(b: &mut test::Bencher) {
     let mut deq = VecDeque::<i32>::with_capacity(101);
 
@@ -43,7 +43,7 @@ fn bench_pop_back_100(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_pop_front_100(b: &mut test::Bencher) {
     let mut deq = VecDeque::<i32>::with_capacity(101);
 
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 5365c9d0168..7aaa91ee10d 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -109,7 +109,7 @@
 #![feature(ptr_offset_from)]
 #![feature(rustc_attrs)]
 #![feature(receiver_trait)]
-#![feature(specialization)]
+#![feature(min_specialization)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(str_internals)]
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index a8e19c9cbaa..d46bf81f996 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -1,7 +1,7 @@
 #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")]
 #![doc(hidden)]
 
-use core::alloc::MemoryBlock;
+use core::alloc::{LayoutErr, MemoryBlock};
 use core::cmp;
 use core::mem::{self, ManuallyDrop, MaybeUninit};
 use core::ops::Drop;
@@ -211,82 +211,6 @@ impl<T, A: AllocRef> RawVec<T, A> {
         }
     }
 
-    /// Doubles the size of the type's backing allocation. This is common enough
-    /// to want to do that it's easiest to just have a dedicated method. Slightly
-    /// more efficient logic can be provided for this than the general case.
-    ///
-    /// This function is ideal for when pushing elements one-at-a-time because
-    /// you don't need to incur the costs of the more general computations
-    /// reserve needs to do to guard against overflow. You do however need to
-    /// manually check if your `len == capacity`.
-    ///
-    /// # Panics
-    ///
-    /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
-    ///   all `usize::MAX` slots in your imaginary buffer.
-    /// * Panics on 32-bit platforms if the requested capacity exceeds
-    ///   `isize::MAX` bytes.
-    ///
-    /// # Aborts
-    ///
-    /// Aborts on OOM
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(raw_vec_internals)]
-    /// # extern crate alloc;
-    /// # use std::ptr;
-    /// # use alloc::raw_vec::RawVec;
-    /// struct MyVec<T> {
-    ///     buf: RawVec<T>,
-    ///     len: usize,
-    /// }
-    ///
-    /// impl<T> MyVec<T> {
-    ///     pub fn push(&mut self, elem: T) {
-    ///         if self.len == self.buf.capacity() { self.buf.double(); }
-    ///         // double would have aborted or panicked if the len exceeded
-    ///         // `isize::MAX` so this is safe to do unchecked now.
-    ///         unsafe {
-    ///             ptr::write(self.buf.ptr().add(self.len), elem);
-    ///         }
-    ///         self.len += 1;
-    ///     }
-    /// }
-    /// # fn main() {
-    /// #   let mut vec = MyVec { buf: RawVec::new(), len: 0 };
-    /// #   vec.push(1);
-    /// # }
-    /// ```
-    #[inline(never)]
-    #[cold]
-    pub fn double(&mut self) {
-        match self.grow(Double, MayMove, Uninitialized) {
-            Err(CapacityOverflow) => capacity_overflow(),
-            Err(AllocError { layout, .. }) => handle_alloc_error(layout),
-            Ok(()) => { /* yay */ }
-        }
-    }
-
-    /// Attempts to double the size of the type's backing allocation in place. This is common
-    /// enough to want to do that it's easiest to just have a dedicated method. Slightly
-    /// more efficient logic can be provided for this than the general case.
-    ///
-    /// Returns `true` if the reallocation attempt has succeeded.
-    ///
-    /// # Panics
-    ///
-    /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
-    ///   all `usize::MAX` slots in your imaginary buffer.
-    /// * Panics on 32-bit platforms if the requested capacity exceeds
-    ///   `isize::MAX` bytes.
-    #[inline(never)]
-    #[cold]
-    pub fn double_in_place(&mut self) -> bool {
-        self.grow(Double, InPlace, Uninitialized).is_ok()
-    }
-
     /// Ensures that the buffer contains at least enough space to hold
     /// `used_capacity + needed_extra_capacity` elements. If it doesn't already have
     /// enough capacity, will reallocate enough space plus comfortable slack
@@ -354,7 +278,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
         needed_extra_capacity: usize,
     ) -> Result<(), TryReserveError> {
         if self.needs_to_grow(used_capacity, needed_extra_capacity) {
-            self.grow(Amortized { used_capacity, needed_extra_capacity }, MayMove, Uninitialized)
+            self.grow_amortized(used_capacity, needed_extra_capacity, MayMove)
         } else {
             Ok(())
         }
@@ -381,8 +305,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
         // This is more readable than putting this in one line:
         // `!self.needs_to_grow(...) || self.grow(...).is_ok()`
         if self.needs_to_grow(used_capacity, needed_extra_capacity) {
-            self.grow(Amortized { used_capacity, needed_extra_capacity }, InPlace, Uninitialized)
-                .is_ok()
+            self.grow_amortized(used_capacity, needed_extra_capacity, InPlace).is_ok()
         } else {
             true
         }
@@ -423,7 +346,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
         needed_extra_capacity: usize,
     ) -> Result<(), TryReserveError> {
         if self.needs_to_grow(used_capacity, needed_extra_capacity) {
-            self.grow(Exact { used_capacity, needed_extra_capacity }, MayMove, Uninitialized)
+            self.grow_exact(used_capacity, needed_extra_capacity)
         } else {
             Ok(())
         }
@@ -448,14 +371,6 @@ impl<T, A: AllocRef> RawVec<T, A> {
     }
 }
 
-#[derive(Copy, Clone)]
-enum Strategy {
-    Double,
-    Amortized { used_capacity: usize, needed_extra_capacity: usize },
-    Exact { used_capacity: usize, needed_extra_capacity: usize },
-}
-use Strategy::*;
-
 impl<T, A: AllocRef> RawVec<T, A> {
     /// Returns if the buffer needs to grow to fulfill the needed extra capacity.
     /// Mainly used to make inlining reserve-calls possible without inlining `grow`.
@@ -473,68 +388,59 @@ impl<T, A: AllocRef> RawVec<T, A> {
         self.cap = Self::capacity_from_bytes(memory.size);
     }
 
-    /// Single method to handle all possibilities of growing the buffer.
-    fn grow(
+    // This method is usually instantiated many times. So we want it to be as
+    // small as possible, to improve compile times. But we also want as much of
+    // its contents to be statically computable as possible, to make the
+    // generated code run faster. Therefore, this method is carefully written
+    // so that all of the code that depends on `T` is within it, while as much
+    // of the code that doesn't depend on `T` as possible is in functions that
+    // are non-generic over `T`.
+    fn grow_amortized(
         &mut self,
-        strategy: Strategy,
+        used_capacity: usize,
+        needed_extra_capacity: usize,
         placement: ReallocPlacement,
-        init: AllocInit,
     ) -> Result<(), TryReserveError> {
-        let elem_size = mem::size_of::<T>();
-        if elem_size == 0 {
+        if mem::size_of::<T>() == 0 {
             // Since we return a capacity of `usize::MAX` when `elem_size` is
             // 0, getting to here necessarily means the `RawVec` is overfull.
             return Err(CapacityOverflow);
         }
-        let new_layout = match strategy {
-            Double => unsafe {
-                // Since we guarantee that we never allocate more than `isize::MAX` bytes,
-                // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow.
-                // Additionally the alignment will never be too large as to "not be satisfiable",
-                // so `Layout::from_size_align` will always return `Some`.
-                //
-                // TL;DR, we bypass runtime checks due to dynamic assertions in this module,
-                // allowing us to use `from_size_align_unchecked`.
-                let cap = if self.cap == 0 {
-                    // Skip to 4 because tiny `Vec`'s are dumb; but not if that would cause overflow.
-                    if elem_size > usize::MAX / 8 { 1 } else { 4 }
-                } else {
-                    self.cap * 2
-                };
-                Layout::from_size_align_unchecked(cap * elem_size, mem::align_of::<T>())
-            },
-            Amortized { used_capacity, needed_extra_capacity } => {
-                // Nothing we can really do about these checks, sadly.
-                let required_cap =
-                    used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
-                // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
-                let double_cap = self.cap * 2;
-                // `double_cap` guarantees exponential growth.
-                let cap = cmp::max(double_cap, required_cap);
-                Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?
-            }
-            Exact { used_capacity, needed_extra_capacity } => {
-                let cap =
-                    used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
-                Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?
-            }
-        };
-        alloc_guard(new_layout.size())?;
 
-        let memory = if let Some((ptr, old_layout)) = self.current_memory() {
-            debug_assert_eq!(old_layout.align(), new_layout.align());
-            unsafe {
-                self.alloc
-                    .grow(ptr, old_layout, new_layout.size(), placement, init)
-                    .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
-            }
-        } else {
-            match placement {
-                MayMove => self.alloc.alloc(new_layout, init),
-                InPlace => Err(AllocErr),
-            }
-            .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
-        };
+        // Nothing we can really do about these checks, sadly.
+        let required_cap =
+            used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
+        // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
+        let double_cap = self.cap * 2;
+        // `double_cap` guarantees exponential growth.
+        let cap = cmp::max(double_cap, required_cap);
+        let new_layout = Layout::array::<T>(cap);
+
+        // `finish_grow` is non-generic over `T`.
+        let memory = finish_grow(new_layout, placement, self.current_memory(), &mut self.alloc)?;
+        self.set_memory(memory);
+        Ok(())
+    }
+
+    // The constraints on this method are much the same as those on
+    // `grow_amortized`, but this method is usually instantiated less often so
+    // it's less critical.
+    fn grow_exact(
+        &mut self,
+        used_capacity: usize,
+        needed_extra_capacity: usize,
+    ) -> Result<(), TryReserveError> {
+        if mem::size_of::<T>() == 0 {
+            // Since we return a capacity of `usize::MAX` when the type size is
+            // 0, getting to here necessarily means the `RawVec` is overfull.
+            return Err(CapacityOverflow);
+        }
+
+        let cap = used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
+        let new_layout = Layout::array::<T>(cap);
+
+        // `finish_grow` is non-generic over `T`.
+        let memory = finish_grow(new_layout, MayMove, self.current_memory(), &mut self.alloc)?;
         self.set_memory(memory);
         Ok(())
     }
@@ -562,6 +468,38 @@ impl<T, A: AllocRef> RawVec<T, A> {
     }
 }
 
+// This function is outside `RawVec` to minimize compile times. See the comment
+// above `RawVec::grow_amortized` for details. (The `A` parameter isn't
+// significant, because the number of different `A` types seen in practice is
+// much smaller than the number of `T` types.)
+fn finish_grow<A>(
+    new_layout: Result<Layout, LayoutErr>,
+    placement: ReallocPlacement,
+    current_memory: Option<(NonNull<u8>, Layout)>,
+    alloc: &mut A,
+) -> Result<MemoryBlock, TryReserveError>
+where
+    A: AllocRef,
+{
+    // Check for the error here to minimize the size of `RawVec::grow_*`.
+    let new_layout = new_layout.map_err(|_| CapacityOverflow)?;
+
+    alloc_guard(new_layout.size())?;
+
+    let memory = if let Some((ptr, old_layout)) = current_memory {
+        debug_assert_eq!(old_layout.align(), new_layout.align());
+        unsafe { alloc.grow(ptr, old_layout, new_layout.size(), placement, Uninitialized) }
+    } else {
+        match placement {
+            MayMove => alloc.alloc(new_layout, Uninitialized),
+            InPlace => Err(AllocErr),
+        }
+    }
+    .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?;
+
+    Ok(memory)
+}
+
 impl<T> RawVec<T, Global> {
     /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
     ///
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 2f9505ec79f..76213e65bab 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -249,7 +249,7 @@ use core::mem::{self, align_of, align_of_val, forget, size_of_val};
 use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
-use core::slice::{self, from_raw_parts_mut};
+use core::slice::from_raw_parts_mut;
 
 use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout};
 use crate::string::String;
@@ -1221,6 +1221,12 @@ impl<T: ?Sized + PartialEq> RcEqIdent<T> for Rc<T> {
     }
 }
 
+// Hack to allow specializing on `Eq` even though `Eq` has a method.
+#[rustc_unsafe_specialization_marker]
+pub(crate) trait MarkerEq: PartialEq<Self> {}
+
+impl<T: Eq> MarkerEq for T {}
+
 /// We're doing this specialization here, and not as a more general optimization on `&T`, because it
 /// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to
 /// store large values, that are slow to clone, but also heavy to check for equality, causing this
@@ -1229,7 +1235,7 @@ impl<T: ?Sized + PartialEq> RcEqIdent<T> for Rc<T> {
 ///
 /// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized + Eq> RcEqIdent<T> for Rc<T> {
+impl<T: ?Sized + MarkerEq> RcEqIdent<T> for Rc<T> {
     #[inline]
     fn eq(&self, other: &Rc<T>) -> bool {
         Rc::ptr_eq(self, other) || **self == **other
@@ -1548,25 +1554,25 @@ impl<T> iter::FromIterator<T> for Rc<[T]> {
     /// # assert_eq!(&*evens, &*(0..10).collect::<Vec<_>>());
     /// ```
     fn from_iter<I: iter::IntoIterator<Item = T>>(iter: I) -> Self {
-        RcFromIter::from_iter(iter.into_iter())
+        ToRcSlice::to_rc_slice(iter.into_iter())
     }
 }
 
 /// Specialization trait used for collecting into `Rc<[T]>`.
-trait RcFromIter<T, I> {
-    fn from_iter(iter: I) -> Self;
+trait ToRcSlice<T>: Iterator<Item = T> + Sized {
+    fn to_rc_slice(self) -> Rc<[T]>;
 }
 
-impl<T, I: Iterator<Item = T>> RcFromIter<T, I> for Rc<[T]> {
-    default fn from_iter(iter: I) -> Self {
-        iter.collect::<Vec<T>>().into()
+impl<T, I: Iterator<Item = T>> ToRcSlice<T> for I {
+    default fn to_rc_slice(self) -> Rc<[T]> {
+        self.collect::<Vec<T>>().into()
     }
 }
 
-impl<T, I: iter::TrustedLen<Item = T>> RcFromIter<T, I> for Rc<[T]> {
-    default fn from_iter(iter: I) -> Self {
+impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
+    fn to_rc_slice(self) -> Rc<[T]> {
         // This is the case for a `TrustedLen` iterator.
-        let (low, high) = iter.size_hint();
+        let (low, high) = self.size_hint();
         if let Some(high) = high {
             debug_assert_eq!(
                 low,
@@ -1577,29 +1583,15 @@ impl<T, I: iter::TrustedLen<Item = T>> RcFromIter<T, I> for Rc<[T]> {
 
             unsafe {
                 // SAFETY: We need to ensure that the iterator has an exact length and we have.
-                Rc::from_iter_exact(iter, low)
+                Rc::from_iter_exact(self, low)
             }
         } else {
             // Fall back to normal implementation.
-            iter.collect::<Vec<T>>().into()
+            self.collect::<Vec<T>>().into()
         }
     }
 }
 
-impl<'a, T: 'a + Clone> RcFromIter<&'a T, slice::Iter<'a, T>> for Rc<[T]> {
-    fn from_iter(iter: slice::Iter<'a, T>) -> Self {
-        // Delegate to `impl<T: Clone> From<&[T]> for Rc<[T]>`.
-        //
-        // In the case that `T: Copy`, we get to use `ptr::copy_nonoverlapping`
-        // which is even more performant.
-        //
-        // In the fall-back case we have `T: Clone`. This is still better
-        // than the `TrustedLen` implementation as slices have a known length
-        // and so we get to avoid calling `size_hint` and avoid the branching.
-        iter.as_slice().into()
-    }
-}
-
 /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the
 /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
 /// pointer, which returns an [`Option`]`<`[`Rc`]`<T>>`.
@@ -2035,6 +2027,8 @@ trait RcBoxPtr<T: ?Sized> {
         // nevertheless, we insert an abort here to hint LLVM at
         // an otherwise missed optimization.
         if strong == 0 || strong == usize::max_value() {
+            // remove `unsafe` on bootstrap bump
+            #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
             unsafe {
                 abort();
             }
@@ -2061,6 +2055,8 @@ trait RcBoxPtr<T: ?Sized> {
         // nevertheless, we insert an abort here to hint LLVM at
         // an otherwise missed optimization.
         if weak == 0 || weak == usize::max_value() {
+            // remove `unsafe` on bootstrap bump
+            #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
             unsafe {
                 abort();
             }
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 19d289c87fd..2c6d130826b 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -20,7 +20,7 @@ use core::mem::{self, align_of, align_of_val, size_of_val};
 use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
-use core::slice::{self, from_raw_parts_mut};
+use core::slice::from_raw_parts_mut;
 use core::sync::atomic;
 use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
 
@@ -835,12 +835,14 @@ impl<T: ?Sized> Arc<T> {
     ///
     /// unsafe {
     ///     let ptr = Arc::into_raw(five);
-    ///     Arc::decr_strong_count(ptr);
+    ///     Arc::incr_strong_count(ptr);
     ///
-    ///     // This assertion is deterministic because we haven't shared
+    ///     // Those assertions are deterministic because we haven't shared
     ///     // the `Arc` between threads.
     ///     let five = Arc::from_raw(ptr);
-    ///     assert_eq!(0, Arc::strong_count(&five));
+    ///     assert_eq!(2, Arc::strong_count(&five));
+    ///     Arc::decr_strong_count(ptr);
+    ///     assert_eq!(1, Arc::strong_count(&five));
     /// }
     /// ```
     #[inline]
@@ -1094,6 +1096,8 @@ impl<T: ?Sized> Clone for Arc<T> {
         // We abort because such a program is incredibly degenerate, and we
         // don't care to support it.
         if old_size > MAX_REFCOUNT {
+            // remove `unsafe` on bootstrap bump
+            #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
             unsafe {
                 abort();
             }
@@ -1612,6 +1616,8 @@ impl<T: ?Sized> Weak<T> {
 
             // See comments in `Arc::clone` for why we do this (for `mem::forget`).
             if n > MAX_REFCOUNT {
+                // remove `unsafe` on bootstrap bump
+                #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
                 unsafe {
                     abort();
                 }
@@ -1751,6 +1757,7 @@ impl<T: ?Sized> Clone for Weak<T> {
 
         // See comments in Arc::clone() for why we do this (for mem::forget).
         if old_size > MAX_REFCOUNT {
+            #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
             unsafe {
                 abort();
             }
@@ -1852,7 +1859,7 @@ impl<T: ?Sized + PartialEq> ArcEqIdent<T> for Arc<T> {
 ///
 /// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized + Eq> ArcEqIdent<T> for Arc<T> {
+impl<T: ?Sized + crate::rc::MarkerEq> ArcEqIdent<T> for Arc<T> {
     #[inline]
     fn eq(&self, other: &Arc<T>) -> bool {
         Arc::ptr_eq(self, other) || **self == **other
@@ -2178,25 +2185,25 @@ impl<T> iter::FromIterator<T> for Arc<[T]> {
     /// # assert_eq!(&*evens, &*(0..10).collect::<Vec<_>>());
     /// ```
     fn from_iter<I: iter::IntoIterator<Item = T>>(iter: I) -> Self {
-        ArcFromIter::from_iter(iter.into_iter())
+        ToArcSlice::to_arc_slice(iter.into_iter())
     }
 }
 
 /// Specialization trait used for collecting into `Arc<[T]>`.
-trait ArcFromIter<T, I> {
-    fn from_iter(iter: I) -> Self;
+trait ToArcSlice<T>: Iterator<Item = T> + Sized {
+    fn to_arc_slice(self) -> Arc<[T]>;
 }
 
-impl<T, I: Iterator<Item = T>> ArcFromIter<T, I> for Arc<[T]> {
-    default fn from_iter(iter: I) -> Self {
-        iter.collect::<Vec<T>>().into()
+impl<T, I: Iterator<Item = T>> ToArcSlice<T> for I {
+    default fn to_arc_slice(self) -> Arc<[T]> {
+        self.collect::<Vec<T>>().into()
     }
 }
 
-impl<T, I: iter::TrustedLen<Item = T>> ArcFromIter<T, I> for Arc<[T]> {
-    default fn from_iter(iter: I) -> Self {
+impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> for I {
+    fn to_arc_slice(self) -> Arc<[T]> {
         // This is the case for a `TrustedLen` iterator.
-        let (low, high) = iter.size_hint();
+        let (low, high) = self.size_hint();
         if let Some(high) = high {
             debug_assert_eq!(
                 low,
@@ -2207,29 +2214,15 @@ impl<T, I: iter::TrustedLen<Item = T>> ArcFromIter<T, I> for Arc<[T]> {
 
             unsafe {
                 // SAFETY: We need to ensure that the iterator has an exact length and we have.
-                Arc::from_iter_exact(iter, low)
+                Arc::from_iter_exact(self, low)
             }
         } else {
             // Fall back to normal implementation.
-            iter.collect::<Vec<T>>().into()
+            self.collect::<Vec<T>>().into()
         }
     }
 }
 
-impl<'a, T: 'a + Clone> ArcFromIter<&'a T, slice::Iter<'a, T>> for Arc<[T]> {
-    fn from_iter(iter: slice::Iter<'a, T>) -> Self {
-        // Delegate to `impl<T: Clone> From<&[T]> for Arc<[T]>`.
-        //
-        // In the case that `T: Copy`, we get to use `ptr::copy_nonoverlapping`
-        // which is even more performant.
-        //
-        // In the fall-back case we have `T: Clone`. This is still better
-        // than the `TrustedLen` implementation as slices have a known length
-        // and so we get to avoid calling `size_hint` and avoid the branching.
-        iter.as_slice().into()
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> borrow::Borrow<T> for Arc<T> {
     fn borrow(&self) -> &T {
diff --git a/src/liballoc/sync/tests.rs b/src/liballoc/sync/tests.rs
index edc2820ee22..a2bb651e2b7 100644
--- a/src/liballoc/sync/tests.rs
+++ b/src/liballoc/sync/tests.rs
@@ -32,7 +32,6 @@ impl Drop for Canary {
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg_attr(miri, ignore)] // Miri does not support threads
 fn manually_share_arc() {
     let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
     let arc_v = Arc::new(v);
@@ -337,12 +336,13 @@ fn test_ptr_eq() {
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg_attr(miri, ignore)] // Miri does not support threads
 fn test_weak_count_locked() {
     let mut a = Arc::new(atomic::AtomicBool::new(false));
     let a2 = a.clone();
     let t = thread::spawn(move || {
-        for _i in 0..1000000 {
+        // Miri is too slow
+        let count = if cfg!(miri) { 1000 } else { 1000000 };
+        for _i in 0..count {
             Arc::get_mut(&mut a);
         }
         a.store(true, SeqCst);
@@ -351,6 +351,8 @@ fn test_weak_count_locked() {
     while !a2.load(SeqCst) {
         let n = Arc::weak_count(&a2);
         assert!(n < 2, "bad weak count: {}", n);
+        #[cfg(miri)] // Miri's scheduler does not guarantee liveness, and thus needs this hint.
+        atomic::spin_loop_hint();
     }
     t.join().unwrap();
 }
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index cbfbf4d1cd3..d26cd77aae4 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -1619,8 +1619,8 @@ impl<T: Default> Vec<T> {
     #[unstable(feature = "vec_resize_default", issue = "41758")]
     #[rustc_deprecated(
         reason = "This is moving towards being removed in favor \
-        of `.resize_with(Default::default)`.  If you disagree, please comment \
-        in the tracking issue.",
+                  of `.resize_with(Default::default)`.  If you disagree, please comment \
+                  in the tracking issue.",
         since = "1.33.0"
     )]
     pub fn resize_default(&mut self, new_len: usize) {
@@ -1825,6 +1825,7 @@ impl<T: Clone + IsZero> SpecFromElem for T {
     }
 }
 
+#[rustc_specialization_trait]
 unsafe trait IsZero {
     /// Whether this value is zero
     fn is_zero(&self) -> bool;
@@ -1874,9 +1875,12 @@ unsafe impl<T> IsZero for *mut T {
     }
 }
 
-// `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
-// For fat pointers, the bytes that would be the pointer metadata in the `Some` variant
-// are padding in the `None` variant, so ignoring them and zero-initializing instead is ok.
+// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
+// For fat pointers, the bytes that would be the pointer metadata in the `Some`
+// variant are padding in the `None` variant, so ignoring them and
+// zero-initializing instead is ok.
+// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
+// `SpecFromElem`.
 
 unsafe impl<T: ?Sized> IsZero for Option<&T> {
     #[inline]
@@ -1885,13 +1889,6 @@ unsafe impl<T: ?Sized> IsZero for Option<&T> {
     }
 }
 
-unsafe impl<T: ?Sized> IsZero for Option<&mut T> {
-    #[inline]
-    fn is_zero(&self) -> bool {
-        self.is_none()
-    }
-}
-
 unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
     #[inline]
     fn is_zero(&self) -> bool {
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 0f0bd617f43..bbe80c26dcb 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -5,8 +5,7 @@
 //! of individual objects while the arena itself is still alive. The benefit
 //! of an arena is very fast allocation; just a pointer bump.
 //!
-//! This crate implements `TypedArena`, a simple arena that can only hold
-//! objects of a single type.
+//! This crate implements several kinds of arena.
 
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/",
@@ -98,7 +97,13 @@ impl<T> TypedArenaChunk<T> {
     }
 }
 
+// The arenas start with PAGE-sized chunks, and then each new chunk is twice as
+// big as its predecessor, up until we reach HUGE_PAGE-sized chunks, whereupon
+// we stop growing. This scales well, from arenas that are barely used up to
+// arenas that are used for 100s of MiBs. Note also that the chosen sizes match
+// the usual sizes of pages and huge pages on Linux.
 const PAGE: usize = 4096;
+const HUGE_PAGE: usize = 2 * 1024 * 1024;
 
 impl<T> Default for TypedArena<T> {
     /// Creates a new `TypedArena`.
@@ -211,6 +216,9 @@ impl<T> TypedArena<T> {
     #[cold]
     fn grow(&self, n: usize) {
         unsafe {
+            // We need the element size in to convert chunk sizes (ranging from
+            // PAGE to HUGE_PAGE bytes) to element counts.
+            let elem_size = cmp::max(1, mem::size_of::<T>());
             let mut chunks = self.chunks.borrow_mut();
             let (chunk, mut new_capacity);
             if let Some(last_chunk) = chunks.last_mut() {
@@ -221,18 +229,20 @@ impl<T> TypedArena<T> {
                     self.end.set(last_chunk.end());
                     return;
                 } else {
+                    // If the previous chunk's capacity is less than HUGE_PAGE
+                    // bytes, then this chunk will be least double the previous
+                    // chunk's size.
                     new_capacity = last_chunk.storage.capacity();
-                    loop {
+                    if new_capacity < HUGE_PAGE / elem_size {
                         new_capacity = new_capacity.checked_mul(2).unwrap();
-                        if new_capacity >= currently_used_cap + n {
-                            break;
-                        }
                     }
                 }
             } else {
-                let elem_size = cmp::max(1, mem::size_of::<T>());
-                new_capacity = cmp::max(n, PAGE / elem_size);
+                new_capacity = PAGE / elem_size;
             }
+            // Also ensure that this chunk can fit `n`.
+            new_capacity = cmp::max(n, new_capacity);
+
             chunk = TypedArenaChunk::<T>::new(new_capacity);
             self.ptr.set(chunk.start());
             self.end.set(chunk.end());
@@ -347,17 +357,20 @@ impl DroplessArena {
                     self.end.set(last_chunk.end());
                     return;
                 } else {
+                    // If the previous chunk's capacity is less than HUGE_PAGE
+                    // bytes, then this chunk will be least double the previous
+                    // chunk's size.
                     new_capacity = last_chunk.storage.capacity();
-                    loop {
+                    if new_capacity < HUGE_PAGE {
                         new_capacity = new_capacity.checked_mul(2).unwrap();
-                        if new_capacity >= used_bytes + needed_bytes {
-                            break;
-                        }
                     }
                 }
             } else {
-                new_capacity = cmp::max(needed_bytes, PAGE);
+                new_capacity = PAGE;
             }
+            // Also ensure that this chunk can fit `needed_bytes`.
+            new_capacity = cmp::max(needed_bytes, new_capacity);
+
             chunk = TypedArenaChunk::<u8>::new(new_capacity);
             self.ptr.set(chunk.start());
             self.end.set(chunk.end());
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index 39df803bbea..79b6304958d 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -446,14 +446,16 @@ impl TypeId {
 /// # Note
 ///
 /// This is intended for diagnostic use. The exact contents and format of the
-/// string are not specified, other than being a best-effort description of the
-/// type. For example, `type_name::<Option<String>>()` could return the
-/// `"Option<String>"` or `"std::option::Option<std::string::String>"`, but not
-/// `"foobar"`. In addition, the output may change between versions of the
-/// compiler.
+/// string returned are not specified, other than being a best-effort
+/// description of the type. For example, amongst the strings
+/// that `type_name::<Option<String>>()` might return are `"Option<String>"` and
+/// `"std::option::Option<std::string::String>"`.
 ///
-/// The type name should not be considered a unique identifier of a type;
-/// multiple types may share the same type name.
+/// The returned string must not be considered to be a unique identifier of a
+/// type as multiple types may map to the same type name. Similarly, there is no
+/// guarantee that all parts of a type will appear in the returned string: for
+/// example, lifetime specifiers are currently not included. In addition, the
+/// output may change between versions of the compiler.
 ///
 /// The current implementation uses the same infrastructure as compiler
 /// diagnostics and debuginfo, but this is not guaranteed.
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 0f2665eba6f..fad3095f8a3 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -133,10 +133,9 @@
 //! `Cell<T>`.
 //!
 //! ```
-//! #![feature(core_intrinsics)]
 //! use std::cell::Cell;
 //! use std::ptr::NonNull;
-//! use std::intrinsics::abort;
+//! use std::process::abort;
 //! use std::marker::PhantomData;
 //!
 //! struct Rc<T: ?Sized> {
@@ -173,7 +172,7 @@
 //!             .strong
 //!             .set(self.strong()
 //!                      .checked_add(1)
-//!                      .unwrap_or_else(|| unsafe { abort() }));
+//!                      .unwrap_or_else(|| abort() ));
 //!     }
 //! }
 //!
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 962bcbe6198..43512f7a236 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -918,7 +918,7 @@ extern "rust-intrinsic" {
 
     /// Aborts the execution of the process.
     ///
-    /// The stabilized version of this intrinsic is
+    /// A more user-friendly and stable version of this operation is
     /// [`std::process::abort`](../../std/process/fn.abort.html).
     pub fn abort() -> !;
 
diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs
index bb68184c8dd..d74df82bddd 100644
--- a/src/libcore/iter/range.rs
+++ b/src/libcore/iter/range.rs
@@ -4,47 +4,182 @@ use crate::ops::{self, Add, Sub, Try};
 
 use super::{FusedIterator, TrustedLen};
 
-/// Objects that can be stepped over in both directions.
+/// Objects that have a notion of *successor* and *predecessor* operations.
 ///
-/// The `steps_between` function provides a way to efficiently compare
-/// two `Step` objects.
-#[unstable(
-    feature = "step_trait",
-    reason = "likely to be replaced by finer-grained traits",
-    issue = "42168"
-)]
-pub trait Step: Clone + PartialOrd + Sized {
-    /// Returns the number of steps between two step objects. The count is
-    /// inclusive of `start` and exclusive of `end`.
-    ///
-    /// Returns `None` if it is not possible to calculate `steps_between`
-    /// without overflow.
+/// The *successor* operation moves towards values that compare greater.
+/// The *predecessor* operation moves towards values that compare lesser.
+///
+/// # Safety
+///
+/// This trait is `unsafe` because its implementation must be correct for
+/// the safety of `unsafe trait TrustedLen` implementations, and the results
+/// of using this trait can otherwise be trusted by `unsafe` code to be correct
+/// and fulfill the listed obligations.
+#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+pub unsafe trait Step: Clone + PartialOrd + Sized {
+    /// Returns the number of *successor* steps required to get from `start` to `end`.
+    ///
+    /// Returns `None` if the number of steps would overflow `usize`
+    /// (or is infinite, or if `end` would never be reached).
+    ///
+    /// # Invariants
+    ///
+    /// For any `a`, `b`, and `n`:
+    ///
+    /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::forward_checked(&a, n) == Some(b)`
+    /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward_checked(&a, n) == Some(a)`
+    /// * `steps_between(&a, &b) == Some(n)` only if `a <= b`
+    ///   * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b`
+    ///   * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
+    ///     this is the case wheen it would require more than `usize::MAX` steps to get to `b`
+    /// * `steps_between(&a, &b) == None` if `a > b`
     fn steps_between(start: &Self, end: &Self) -> Option<usize>;
 
-    /// Replaces this step with `1`, returning a clone of itself.
+    /// Returns the value that would be obtained by taking the *successor*
+    /// of `self` `count` times.
+    ///
+    /// If this would overflow the range of values supported by `Self`, returns `None`.
     ///
-    /// The output of this method should always be greater than the output of replace_zero.
-    fn replace_one(&mut self) -> Self;
+    /// # Invariants
+    ///
+    /// For any `a`, `n`, and `m`:
+    ///
+    /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))`
+    ///
+    /// For any `a`, `n`, and `m` where `n + m` does not overflow:
+    ///
+    /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, n + m)`
+    ///
+    /// For any `a` and `n`:
+    ///
+    /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
+    ///   * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
+    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
+    fn forward_checked(start: Self, count: usize) -> Option<Self>;
 
-    /// Replaces this step with `0`, returning a clone of itself.
+    /// Returns the value that would be obtained by taking the *successor*
+    /// of `self` `count` times.
+    ///
+    /// If this would overflow the range of values supported by `Self`,
+    /// this function is allowed to panic, wrap, or saturate.
+    /// The suggested behavior is to panic when debug assertions are enabled,
+    /// and to wrap or saturate otherwise.
     ///
-    /// The output of this method should always be less than the output of replace_one.
-    fn replace_zero(&mut self) -> Self;
+    /// Unsafe code should not rely on the correctness of behavior after overflow.
+    ///
+    /// # Invariants
+    ///
+    /// For any `a`, `n`, and `m`, where no overflow occurs:
+    ///
+    /// * `Step::forward(Step::forward(a, n), m) == Step::forward(a, n + m)`
+    ///
+    /// For any `a` and `n`, where no overflow occurs:
+    ///
+    /// * `Step::forward_checked(a, n) == Some(Step::forward(a, n))`
+    /// * `Step::forward(a, n) == (0..n).fold(a, |x, _| Step::forward(x, 1))`
+    ///   * Corollary: `Step::forward(a, 0) == a`
+    /// * `Step::forward(a, n) >= a`
+    /// * `Step::backward(Step::forward(a, n), n) == a`
+    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
+    fn forward(start: Self, count: usize) -> Self {
+        Step::forward_checked(start, count).expect("overflow in `Step::forward`")
+    }
 
-    /// Adds one to this step, returning the result.
-    fn add_one(&self) -> Self;
+    /// Returns the value that would be obtained by taking the *successor*
+    /// of `self` `count` times.
+    ///
+    /// # Safety
+    ///
+    /// It is undefined behavior for this operation to overflow the
+    /// range of values supported by `Self`. If you cannot guarantee that this
+    /// will not overflow, use `forward` or `forward_checked` instead.
+    ///
+    /// # Invariants
+    ///
+    /// For any `a`:
+    ///
+    /// * if there exists `b` such that `b > a`, it is safe to call `Step::forward_unchecked(a, 1)`
+    /// * if there exists `b`, `n` such that `steps_between(&a, &b) == Some(n)`,
+    ///   it is safe to call `Step::forward_unchecked(a, m)` for any `m <= n`.
+    ///
+    /// For any `a` and `n`, where no overflow occurs:
+    ///
+    /// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)`
+    #[unstable(feature = "unchecked_math", reason = "niche optimization path", issue = "none")]
+    unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
+        Step::forward(start, count)
+    }
 
-    /// Subtracts one to this step, returning the result.
-    fn sub_one(&self) -> Self;
+    /// Returns the value that would be obtained by taking the *successor*
+    /// of `self` `count` times.
+    ///
+    /// If this would overflow the range of values supported by `Self`, returns `None`.
+    ///
+    /// # Invariants
+    ///
+    /// For any `a`, `n`, and `m`:
+    ///
+    /// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) == n.checked_add(m).and_then(|x| Step::backward_checked(a, x))`
+    /// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) == try { Step::backward_checked(a, n.checked_add(m)?) }`
+    ///
+    /// For any `a` and `n`:
+    ///
+    /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
+    ///   * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
+    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
+    fn backward_checked(start: Self, count: usize) -> Option<Self>;
 
-    /// Adds a `usize`, returning `None` on overflow.
-    fn add_usize(&self, n: usize) -> Option<Self>;
+    /// Returns the value that would be obtained by taking the *predecessor*
+    /// of `self` `count` times.
+    ///
+    /// If this would overflow the range of values supported by `Self`,
+    /// this function is allowed to panic, wrap, or saturate.
+    /// The suggested behavior is to panic when debug assertions are enabled,
+    /// and to wrap or saturate otherwise.
+    ///
+    /// Unsafe code should not rely on the correctness of behavior after overflow.
+    ///
+    /// # Invariants
+    ///
+    /// For any `a`, `n`, and `m`, where no overflow occurs:
+    ///
+    /// * `Step::backward(Step::backward(a, n), m) == Step::backward(a, n + m)`
+    ///
+    /// For any `a` and `n`, where no overflow occurs:
+    ///
+    /// * `Step::backward_checked(a, n) == Some(Step::backward(a, n))`
+    /// * `Step::backward(a, n) == (0..n).fold(a, |x, _| Step::backward(x, 1))`
+    ///   * Corollary: `Step::backward(a, 0) == a`
+    /// * `Step::backward(a, n) <= a`
+    /// * `Step::forward(Step::backward(a, n), n) == a`
+    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
+    fn backward(start: Self, count: usize) -> Self {
+        Step::backward_checked(start, count).expect("overflow in `Step::backward`")
+    }
 
-    /// Subtracts a `usize`, returning `None` on underflow.
-    fn sub_usize(&self, n: usize) -> Option<Self> {
-        // this default implementation makes the addition of `sub_usize` a non-breaking change
-        let _ = n;
-        unimplemented!()
+    /// Returns the value that would be obtained by taking the *predecessor*
+    /// of `self` `count` times.
+    ///
+    /// # Safety
+    ///
+    /// It is undefined behavior for this operation to overflow the
+    /// range of values supported by `Self`. If you cannot guarantee that this
+    /// will not overflow, use `backward` or `backward_checked` instead.
+    ///
+    /// # Invariants
+    ///
+    /// For any `a`:
+    ///
+    /// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)`
+    /// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`,
+    ///   it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`.
+    ///
+    /// For any `a` and `n`, where no overflow occurs:
+    ///
+    /// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)`
+    #[unstable(feature = "unchecked_math", reason = "niche optimization path", issue = "none")]
+    unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
+        Step::backward(start, count)
     }
 }
 
@@ -52,127 +187,218 @@ pub trait Step: Clone + PartialOrd + Sized {
 macro_rules! step_identical_methods {
     () => {
         #[inline]
-        fn replace_one(&mut self) -> Self {
-            mem::replace(self, 1)
+        unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
+            start.unchecked_add(n as Self)
         }
 
         #[inline]
-        fn replace_zero(&mut self) -> Self {
-            mem::replace(self, 0)
+        unsafe fn backward_unchecked(start: Self, n: usize) -> Self {
+            start.unchecked_sub(n as Self)
         }
 
         #[inline]
-        fn add_one(&self) -> Self {
-            Add::add(*self, 1)
+        fn forward(start: Self, n: usize) -> Self {
+            // In debug builds, trigger a panic on overflow.
+            // This should optimize completely out in release builds.
+            if Self::forward_checked(start, n).is_none() {
+                let _ = Add::add(Self::MAX, 1);
+            }
+            // Do wrapping math to allow e.g. `Step::forward(-128i8, 255)`.
+            start.wrapping_add(n as Self)
         }
 
         #[inline]
-        fn sub_one(&self) -> Self {
-            Sub::sub(*self, 1)
+        fn backward(start: Self, n: usize) -> Self {
+            // In debug builds, trigger a panic on overflow.
+            // This should optimize completely out in release builds.
+            if Self::backward_checked(start, n).is_none() {
+                let _ = Sub::sub(Self::MIN, 1);
+            }
+            // Do wrapping math to allow e.g. `Step::backward(127i8, 255)`.
+            start.wrapping_sub(n as Self)
         }
     };
 }
 
-macro_rules! step_impl_unsigned {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "step_trait",
-                   reason = "likely to be replaced by finer-grained traits",
-                   issue = "42168")]
-        impl Step for $t {
-            #[inline]
-            fn steps_between(start: &$t, end: &$t) -> Option<usize> {
-                if *start < *end {
-                    usize::try_from(*end - *start).ok()
-                } else {
-                    Some(0)
+macro_rules! step_integer_impls {
+    {
+        narrower than or same width as usize:
+            $( [ $u_narrower:ident $i_narrower:ident ] ),+;
+        wider than usize:
+            $( [ $u_wider:ident $i_wider:ident ] ),+;
+    } => {
+        $(
+            #[allow(unreachable_patterns)]
+            #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+            unsafe impl Step for $u_narrower {
+                step_identical_methods!();
+
+                #[inline]
+                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                    if *start <= *end {
+                        // This relies on $u_narrower <= usize
+                        Some((*end - *start) as usize)
+                    } else {
+                        None
+                    }
                 }
-            }
 
-            #[inline]
-            #[allow(unreachable_patterns)]
-            fn add_usize(&self, n: usize) -> Option<Self> {
-                match <$t>::try_from(n) {
-                    Ok(n_as_t) => self.checked_add(n_as_t),
-                    Err(_) => None,
+                #[inline]
+                fn forward_checked(start: Self, n: usize) -> Option<Self> {
+                    match Self::try_from(n) {
+                        Ok(n) => start.checked_add(n),
+                        Err(_) => None, // if n is out of range, `unsigned_start + n` is too
+                    }
+                }
+
+                #[inline]
+                fn backward_checked(start: Self, n: usize) -> Option<Self> {
+                    match Self::try_from(n) {
+                        Ok(n) => start.checked_sub(n),
+                        Err(_) => None, // if n is out of range, `unsigned_start - n` is too
+                    }
                 }
             }
 
-            #[inline]
             #[allow(unreachable_patterns)]
-            fn sub_usize(&self, n: usize) -> Option<Self> {
-                match <$t>::try_from(n) {
-                    Ok(n_as_t) => self.checked_sub(n_as_t),
-                    Err(_) => None,
+            #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+            unsafe impl Step for $i_narrower {
+                step_identical_methods!();
+
+                #[inline]
+                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                    if *start <= *end {
+                        // This relies on $i_narrower <= usize
+                        //
+                        // Casting to isize extends the width but preserves the sign.
+                        // Use wrapping_sub in isize space and cast to usize to compute
+                        // the difference that may not fit inside the range of isize.
+                        Some((*end as isize).wrapping_sub(*start as isize) as usize)
+                    } else {
+                        None
+                    }
                 }
-            }
 
-            step_identical_methods!();
-        }
-    )*)
-}
-macro_rules! step_impl_signed {
-    ($( [$t:ty : $unsigned:ty] )*) => ($(
-        #[unstable(feature = "step_trait",
-                   reason = "likely to be replaced by finer-grained traits",
-                   issue = "42168")]
-        impl Step for $t {
-            #[inline]
-            fn steps_between(start: &$t, end: &$t) -> Option<usize> {
-                if *start < *end {
-                    // Use .wrapping_sub and cast to unsigned to compute the
-                    // difference that may not fit inside the range of $t.
-                    usize::try_from(end.wrapping_sub(*start) as $unsigned).ok()
-                } else {
-                    Some(0)
+                #[inline]
+                fn forward_checked(start: Self, n: usize) -> Option<Self> {
+                    match $u_narrower::try_from(n) {
+                        Ok(n) => {
+                            // Wrapping handles cases like
+                            // `Step::forward(-120_i8, 200) == Some(80_i8)`,
+                            // even though 200 is out of range for i8.
+                            let wrapped = start.wrapping_add(n as Self);
+                            if wrapped >= start {
+                                Some(wrapped)
+                            } else {
+                                None // Addition overflowed
+                            }
+                        }
+                        // If n is out of range of e.g. u8,
+                        // then it is bigger than the entire range for i8 is wide
+                        // so `any_i8 + n` necessarily overflows i8.
+                        Err(_) => None,
+                    }
+                }
+
+                #[inline]
+                fn backward_checked(start: Self, n: usize) -> Option<Self> {
+                    match $u_narrower::try_from(n) {
+                        Ok(n) => {
+                            // Wrapping handles cases like
+                            // `Step::forward(-120_i8, 200) == Some(80_i8)`,
+                            // even though 200 is out of range for i8.
+                            let wrapped = start.wrapping_sub(n as Self);
+                            if wrapped <= start {
+                                Some(wrapped)
+                            } else {
+                                None // Subtraction overflowed
+                            }
+                        }
+                        // If n is out of range of e.g. u8,
+                        // then it is bigger than the entire range for i8 is wide
+                        // so `any_i8 - n` necessarily overflows i8.
+                        Err(_) => None,
+                    }
                 }
             }
+        )+
 
-            #[inline]
+        $(
             #[allow(unreachable_patterns)]
-            fn add_usize(&self, n: usize) -> Option<Self> {
-                match <$unsigned>::try_from(n) {
-                    Ok(n_as_unsigned) => {
-                        // Wrapping in unsigned space handles cases like
-                        // `-120_i8.add_usize(200) == Some(80_i8)`,
-                        // even though 200_usize is out of range for i8.
-                        let wrapped = (*self as $unsigned).wrapping_add(n_as_unsigned) as $t;
-                        if wrapped >= *self {
-                            Some(wrapped)
-                        } else {
-                            None  // Addition overflowed
-                        }
+            #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+            unsafe impl Step for $u_wider {
+                step_identical_methods!();
+
+                #[inline]
+                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                    if *start <= *end {
+                        usize::try_from(*end - *start).ok()
+                    } else {
+                        None
                     }
-                    Err(_) => None,
+                }
+
+                #[inline]
+                fn forward_checked(start: Self, n: usize) -> Option<Self> {
+                    start.checked_add(n as Self)
+                }
+
+                #[inline]
+                fn backward_checked(start: Self, n: usize) -> Option<Self> {
+                    start.checked_sub(n as Self)
                 }
             }
 
-            #[inline]
             #[allow(unreachable_patterns)]
-            fn sub_usize(&self, n: usize) -> Option<Self> {
-                match <$unsigned>::try_from(n) {
-                    Ok(n_as_unsigned) => {
-                        // Wrapping in unsigned space handles cases like
-                        // `80_i8.sub_usize(200) == Some(-120_i8)`,
-                        // even though 200_usize is out of range for i8.
-                        let wrapped = (*self as $unsigned).wrapping_sub(n_as_unsigned) as $t;
-                        if wrapped <= *self {
-                            Some(wrapped)
-                        } else {
-                            None  // Subtraction underflowed
+            #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+            unsafe impl Step for $i_wider {
+                step_identical_methods!();
+
+                #[inline]
+                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                    if *start <= *end {
+                        match end.checked_sub(*start) {
+                            Some(result) => usize::try_from(result).ok(),
+                            // If the difference is too big for e.g. i128,
+                            // it's also gonna be too big for usize with fewer bits.
+                            None => None,
                         }
+                    } else {
+                        None
                     }
-                    Err(_) => None,
+                }
+
+                #[inline]
+                fn forward_checked(start: Self, n: usize) -> Option<Self> {
+                    start.checked_add(n as Self)
+                }
+
+                #[inline]
+                fn backward_checked(start: Self, n: usize) -> Option<Self> {
+                    start.checked_sub(n as Self)
                 }
             }
+        )+
+    };
+}
 
-            step_identical_methods!();
-        }
-    )*)
+#[cfg(target_pointer_width = "64")]
+step_integer_impls! {
+    narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize];
+    wider than usize: [u128 i128];
 }
 
-step_impl_unsigned!(usize u8 u16 u32 u64 u128);
-step_impl_signed!([isize: usize][i8: u8][i16: u16]);
-step_impl_signed!([i32: u32][i64: u64][i128: u128]);
+#[cfg(target_pointer_width = "32")]
+step_integer_impls! {
+    narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [usize isize];
+    wider than usize: [u64 i64], [u128 i128];
+}
+
+#[cfg(target_pointer_width = "16")]
+step_integer_impls! {
+    narrower than or same width as usize: [u8 i8], [u16 i16], [usize isize];
+    wider than usize: [u32 i32], [u64 i64], [u128 i128];
+}
 
 macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
@@ -188,20 +414,6 @@ macro_rules! range_incl_exact_iter_impl {
     )*)
 }
 
-macro_rules! range_trusted_len_impl {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "trusted_len", issue = "37572")]
-        unsafe impl TrustedLen for ops::Range<$t> { }
-    )*)
-}
-
-macro_rules! range_incl_trusted_len_impl {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "trusted_len", issue = "37572")]
-        unsafe impl TrustedLen for ops::RangeInclusive<$t> { }
-    )*)
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Step> Iterator for ops::Range<A> {
     type Item = A;
@@ -209,16 +421,12 @@ impl<A: Step> Iterator for ops::Range<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
         if self.start < self.end {
-            // We check for overflow here, even though it can't actually
-            // happen. Adding this check does however help llvm vectorize loops
-            // for some ranges that don't get vectorized otherwise,
-            // and this won't actually result in an extra check in an optimized build.
-            if let Some(mut n) = self.start.add_usize(1) {
-                mem::swap(&mut n, &mut self.start);
-                Some(n)
-            } else {
-                None
-            }
+            // SAFETY: just checked precondition
+            // We use the unchecked version here, because
+            // this helps LLVM vectorize loops for some ranges
+            // that don't get vectorized otherwise.
+            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+            Some(mem::replace(&mut self.start, n))
         } else {
             None
         }
@@ -226,17 +434,19 @@ impl<A: Step> Iterator for ops::Range<A> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        match Step::steps_between(&self.start, &self.end) {
-            Some(hint) => (hint, Some(hint)),
-            None => (usize::MAX, None),
+        if self.start < self.end {
+            let hint = Step::steps_between(&self.start, &self.end);
+            (hint.unwrap_or(usize::MAX), hint)
+        } else {
+            (0, Some(0))
         }
     }
 
     #[inline]
     fn nth(&mut self, n: usize) -> Option<A> {
-        if let Some(plus_n) = self.start.add_usize(n) {
+        if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
             if plus_n < self.end {
-                self.start = plus_n.add_one();
+                self.start = Step::forward(plus_n.clone(), 1);
                 return Some(plus_n);
             }
         }
@@ -262,25 +472,42 @@ impl<A: Step> Iterator for ops::Range<A> {
 }
 
 // These macros generate `ExactSizeIterator` impls for various range types.
-// Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
-// because they cannot guarantee having a length <= usize::MAX, which is
-// required by ExactSizeIterator.
-range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
-range_incl_exact_iter_impl!(u8 u16 i8 i16);
-
-// These macros generate `TrustedLen` impls.
 //
-// They need to guarantee that .size_hint() is either exact, or that
-// the upper bound is None when it does not fit the type limits.
-range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
-range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
+// * `ExactSizeIterator::len` is required to always return an exact `usize`,
+//   so no range can be longer than `usize::MAX`.
+// * For integer types in `Range<_>` this is the case for types narrower than or as wide as `usize`.
+//   For integer types in `RangeInclusive<_>`
+//   this is the case for types *strictly narrower* than `usize`
+//   since e.g. `(0..=u64::MAX).len()` would be `u64::MAX + 1`.
+range_exact_iter_impl! {
+    usize u8 u16
+    isize i8 i16
+
+    // These are incorect per the reasoning above,
+    // but removing them would be a breaking change as they were stabilized in Rust 1.0.0.
+    // So e.g. `(0..66_000_u32).len()` for example will compile without error or warnings
+    // on 16-bit platforms, but continue to give a wrong result.
+    u32
+    i32
+}
+range_incl_exact_iter_impl! {
+    u8
+    i8
+
+    // These are incorect per the reasoning above,
+    // but removing them would be a breaking change as they were stabilized in Rust 1.26.0.
+    // So e.g. `(0..=u16::MAX).len()` for example will compile without error or warnings
+    // on 16-bit platforms, but continue to give a wrong result.
+    u16
+    i16
+}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Step> DoubleEndedIterator for ops::Range<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
         if self.start < self.end {
-            self.end = self.end.sub_one();
+            self.end = Step::backward(self.end.clone(), 1);
             Some(self.end.clone())
         } else {
             None
@@ -289,9 +516,9 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
 
     #[inline]
     fn nth_back(&mut self, n: usize) -> Option<A> {
-        if let Some(minus_n) = self.end.sub_usize(n) {
+        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
             if minus_n > self.start {
-                self.end = minus_n.sub_one();
+                self.end = Step::backward(minus_n, 1);
                 return Some(self.end.clone());
             }
         }
@@ -301,6 +528,9 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: Step> TrustedLen for ops::Range<A> {}
+
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::Range<A> {}
 
@@ -310,9 +540,8 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
 
     #[inline]
     fn next(&mut self) -> Option<A> {
-        let mut n = self.start.add_one();
-        mem::swap(&mut n, &mut self.start);
-        Some(n)
+        let n = Step::forward(self.start.clone(), 1);
+        Some(mem::replace(&mut self.start, n))
     }
 
     #[inline]
@@ -322,8 +551,16 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
 
     #[inline]
     fn nth(&mut self, n: usize) -> Option<A> {
-        let plus_n = self.start.add_usize(n).expect("overflow in RangeFrom::nth");
-        self.start = plus_n.add_one();
+        // If we would jump over the maximum value, panic immediately.
+        // This is consistent with behavior before the Step redesign,
+        // even though it's inconsistent with n `next` calls.
+        // To get consistent behavior, change it to use `forward` instead.
+        // This change should go through FCP separately to the redesign, so is for now left as a
+        // FIXME: make this consistent
+        let plus_n =
+            Step::forward_checked(self.start.clone(), n).expect("overflow in RangeFrom::nth");
+        // The final step should always be debug-checked.
+        self.start = Step::forward(plus_n.clone(), 1);
         Some(plus_n)
     }
 }
@@ -345,7 +582,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
         }
         let is_iterating = self.start < self.end;
         Some(if is_iterating {
-            let n = self.start.add_one();
+            let n = Step::forward(self.start.clone(), 1);
             mem::replace(&mut self.start, n)
         } else {
             self.exhausted = true;
@@ -371,12 +608,12 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
             return None;
         }
 
-        if let Some(plus_n) = self.start.add_usize(n) {
+        if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
             use crate::cmp::Ordering::*;
 
             match plus_n.partial_cmp(&self.end) {
                 Some(Less) => {
-                    self.start = plus_n.add_one();
+                    self.start = Step::forward(plus_n.clone(), 1);
                     return Some(plus_n);
                 }
                 Some(Equal) => {
@@ -407,7 +644,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
         let mut accum = init;
 
         while self.start < self.end {
-            let n = self.start.add_one();
+            let n = Step::forward(self.start.clone(), 1);
             let n = mem::replace(&mut self.start, n);
             accum = f(accum, n)?;
         }
@@ -446,7 +683,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
         }
         let is_iterating = self.start < self.end;
         Some(if is_iterating {
-            let n = self.end.sub_one();
+            let n = Step::backward(self.end.clone(), 1);
             mem::replace(&mut self.end, n)
         } else {
             self.exhausted = true;
@@ -460,12 +697,12 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
             return None;
         }
 
-        if let Some(minus_n) = self.end.sub_usize(n) {
+        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
             use crate::cmp::Ordering::*;
 
             match minus_n.partial_cmp(&self.start) {
                 Some(Greater) => {
-                    self.end = minus_n.sub_one();
+                    self.end = Step::backward(minus_n.clone(), 1);
                     return Some(minus_n);
                 }
                 Some(Equal) => {
@@ -496,7 +733,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
         let mut accum = init;
 
         while self.start < self.end {
-            let n = self.end.sub_one();
+            let n = Step::backward(self.end.clone(), 1);
             let n = mem::replace(&mut self.end, n);
             accum = f(accum, n)?;
         }
@@ -511,5 +748,8 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {}
+
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index 34ca79154b6..447db405c02 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -333,7 +333,7 @@ pub trait Iterator {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
-        for x in self {
+        while let Some(x) = self.next() {
             if n == 0 {
                 return Some(x);
             }
diff --git a/src/libcore/iter/traits/marker.rs b/src/libcore/iter/traits/marker.rs
index 404cc84495c..a9ba3908c38 100644
--- a/src/libcore/iter/traits/marker.rs
+++ b/src/libcore/iter/traits/marker.rs
@@ -13,6 +13,7 @@
 /// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse
 /// [`Fuse`]: ../../std/iter/struct.Fuse.html
 #[stable(feature = "fused", since = "1.26.0")]
+#[rustc_unsafe_specialization_marker]
 pub trait FusedIterator: Iterator {}
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -38,6 +39,7 @@ impl<I: FusedIterator + ?Sized> FusedIterator for &mut I {}
 /// [`usize::MAX`]: ../../std/usize/constant.MAX.html
 /// [`.size_hint`]: ../../std/iter/trait.Iterator.html#method.size_hint
 #[unstable(feature = "trusted_len", issue = "37572")]
+#[rustc_unsafe_specialization_marker]
 pub unsafe trait TrustedLen: Iterator {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 09a8b417e6e..339b07119c6 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -363,6 +363,13 @@ pub trait StructuralEq {
 /// [impls]: #implementors
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "copy"]
+// FIXME(matthewjasper) This allows copying a type that doesn't implement
+// `Copy` because of unsatisfied lifetime bounds (copying `A<'_>` when only
+// `A<'static>: Copy` and `A<'_>: Clone`).
+// We have this attribute here for now only because there are quite a few
+// existing specializations on `Copy` that already exist in the standard
+// library, and there's no way to safely have this behavior right now.
+#[rustc_unsafe_specialization_marker]
 pub trait Copy: Clone {
     // Empty.
 }
diff --git a/src/libcore/mem/manually_drop.rs b/src/libcore/mem/manually_drop.rs
index 9e5c2b10d0d..18767c482c7 100644
--- a/src/libcore/mem/manually_drop.rs
+++ b/src/libcore/mem/manually_drop.rs
@@ -2,19 +2,23 @@ use crate::ops::{Deref, DerefMut};
 use crate::ptr;
 
 /// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
-///
 /// This wrapper is 0-cost.
 ///
 /// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
 /// As a consequence, it has *no effect* on the assumptions that the compiler makes
-/// about all values being initialized at their type.  In particular, initializing
-/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
+/// about its contents. For example, initializing a `ManuallyDrop<&mut T>`
+/// with [`mem::zeroed`] is undefined behavior.
 /// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
 ///
+/// Note that accessing the value inside a `ManuallyDrop<T>` is safe.
+/// This means that a `ManuallyDrop<T>` whose content has been dropped must not
+/// be exposed through a public safe API.
+/// Correspondingly, `ManuallyDrop::drop` is unsafe.
+///
 /// # Examples
 ///
-/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
-/// the type:
+/// This wrapper can be used to enforce a particular drop order on fields, regardless
+/// of how they are defined in the struct:
 ///
 /// ```rust
 /// use std::mem::ManuallyDrop;
@@ -43,8 +47,18 @@ use crate::ptr;
 /// }
 /// ```
 ///
+/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
+/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
+/// would also be leaked.
+///
+/// In contrast, the automatically-generated compiler drop implementation would have ensured
+/// that all fields are dropped even in the presence of panics. This is especially important when
+/// working with [pinned] data, where reusing the memory without calling the destructor could lead
+/// to Undefined Behaviour.
+///
 /// [`mem::zeroed`]: fn.zeroed.html
 /// [`MaybeUninit<T>`]: union.MaybeUninit.html
+/// [pinned]: ../pin/index.html
 #[stable(feature = "manually_drop", since = "1.20.0")]
 #[lang = "manually_drop"]
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -113,19 +127,28 @@ impl<T> ManuallyDrop<T> {
 }
 
 impl<T: ?Sized> ManuallyDrop<T> {
-    /// Manually drops the contained value.
+    /// Manually drops the contained value. This is exactly equivalent to calling
+    /// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless
+    /// the contained value is a packed struct, the destructor will be called in-place
+    /// without moving the value, and thus can be used to safely drop [pinned] data.
     ///
     /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
     ///
     /// # Safety
     ///
-    /// This function runs the destructor of the contained value and thus the wrapped value
-    /// now represents uninitialized data. It is up to the user of this method to ensure the
-    /// uninitialized data is not actually used.
-    /// In particular, this function can only be called at most once
-    /// for a given instance of `ManuallyDrop<T>`.
+    /// This function runs the destructor of the contained value. Other than changes made by
+    /// the destructor itself, the memory is left unchanged, and so as far as the compiler is
+    /// concerned still holds a bit-pattern which is valid for the type `T`.
+    ///
+    /// However, this "zombie" value should not be exposed to safe code, and this function
+    /// should not be called more than once. To use a value after it's been dropped, or drop
+    /// a value multiple times, can cause Undefined Behavior (depending on what `drop` does).
+    /// This is normally prevented by the type system, but users of `ManuallyDrop` must
+    /// uphold those guarantees without assistance from the compiler.
     ///
     /// [`ManuallyDrop::into_inner`]: #method.into_inner
+    /// [`ptr::drop_in_place`]: ../ptr/fn.drop_in_place.html
+    /// [pinned]: ../pin/index.html
     #[stable(feature = "manually_drop", since = "1.20.0")]
     #[inline]
     pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 4483940c9a7..434569020d2 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -367,7 +367,7 @@ impl f32 {
     /// Infinity (∞).
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const INFINITY: f32 = 1.0_f32 / 0.0_f32;
-    /// Negative infinity (-∞).
+    /// Negative infinity (−∞).
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
 
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index df45e588369..6476ddb4541 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -366,7 +366,7 @@ impl f64 {
     /// Infinity (∞).
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const INFINITY: f64 = 1.0_f64 / 0.0_f64;
-    /// Negative infinity (-∞).
+    /// Negative infinity (−∞).
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
 
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index a259e293b0c..9e1971c9a94 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -750,6 +750,23 @@ $EndFeature, "
         }
 
         doc_comment! {
+            concat!("Unchecked integer addition. Computes `self + rhs, assuming overflow
+cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
+"::max_value()` or `self + rhs < ", stringify!($SelfT), "::min_value()`."),
+            #[unstable(
+                feature = "unchecked_math",
+                reason = "niche optimization path",
+                issue = "none",
+            )]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline]
+            pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+                intrinsics::unchecked_add(self, rhs)
+            }
+        }
+
+        doc_comment! {
             concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if
 overflow occurred.
 
@@ -775,6 +792,23 @@ $EndFeature, "
         }
 
         doc_comment! {
+            concat!("Unchecked integer subtraction. Computes `self - rhs, assuming overflow
+cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
+"::max_value()` or `self - rhs < ", stringify!($SelfT), "::min_value()`."),
+            #[unstable(
+                feature = "unchecked_math",
+                reason = "niche optimization path",
+                issue = "none",
+            )]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline]
+            pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+                intrinsics::unchecked_sub(self, rhs)
+            }
+        }
+
+        doc_comment! {
             concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if
 overflow occurred.
 
@@ -800,6 +834,23 @@ $EndFeature, "
         }
 
         doc_comment! {
+            concat!("Unchecked integer multiplication. Computes `self * rhs, assuming overflow
+cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
+"::max_value()` or `self * rhs < ", stringify!($SelfT), "::min_value()`."),
+            #[unstable(
+                feature = "unchecked_math",
+                reason = "niche optimization path",
+                issue = "none",
+            )]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline]
+            pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+                intrinsics::unchecked_mul(self, rhs)
+            }
+        }
+
+        doc_comment! {
             concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
 or the division results in overflow.
 
@@ -1448,8 +1499,8 @@ any high-order bits of `rhs` that would cause the shift to exceed the bitwidth o
 
 Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
 the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
-The primitive integer types all implement a `rotate_left` function, which may be what you want
-instead.
+The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function,
+which may be what you want instead.
 
 # Examples
 
@@ -1480,8 +1531,8 @@ removes any high-order bits of `rhs` that would cause the shift to exceed the bi
 
 Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
 to the range of the type, rather than the bits shifted out of the LHS being returned to the other
-end. The primitive integer types all implement a `rotate_right` function, which may be what you want
-instead.
+end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
+which may be what you want instead.
 
 # Examples
 
@@ -2937,6 +2988,23 @@ assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeat
         }
 
         doc_comment! {
+            concat!("Unchecked integer addition. Computes `self + rhs, assuming overflow
+cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
+"::max_value()` or `self + rhs < ", stringify!($SelfT), "::min_value()`."),
+            #[unstable(
+                feature = "unchecked_math",
+                reason = "niche optimization path",
+                issue = "none",
+            )]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline]
+            pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+                intrinsics::unchecked_add(self, rhs)
+            }
+        }
+
+        doc_comment! {
             concat!("Checked integer subtraction. Computes `self - rhs`, returning
 `None` if overflow occurred.
 
@@ -2960,6 +3028,23 @@ assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, "
         }
 
         doc_comment! {
+            concat!("Unchecked integer subtraction. Computes `self - rhs, assuming overflow
+cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
+"::max_value()` or `self - rhs < ", stringify!($SelfT), "::min_value()`."),
+            #[unstable(
+                feature = "unchecked_math",
+                reason = "niche optimization path",
+                issue = "none",
+            )]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline]
+            pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+                intrinsics::unchecked_sub(self, rhs)
+            }
+        }
+
+        doc_comment! {
             concat!("Checked integer multiplication. Computes `self * rhs`, returning
 `None` if overflow occurred.
 
@@ -2983,6 +3068,23 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, "
         }
 
         doc_comment! {
+            concat!("Unchecked integer multiplication. Computes `self * rhs, assuming overflow
+cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
+"::max_value()` or `self * rhs < ", stringify!($SelfT), "::min_value()`."),
+            #[unstable(
+                feature = "unchecked_math",
+                reason = "niche optimization path",
+                issue = "none",
+            )]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline]
+            pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+                intrinsics::unchecked_mul(self, rhs)
+            }
+        }
+
+        doc_comment! {
             concat!("Checked integer division. Computes `self / rhs`, returning `None`
 if `rhs == 0`.
 
@@ -3508,8 +3610,8 @@ Note that this is *not* the same as a rotate-left; the
 RHS of a wrapping shift-left is restricted to the range
 of the type, rather than the bits shifted out of the LHS
 being returned to the other end. The primitive integer
-types all implement a `rotate_left` function, which may
-be what you want instead.
+types all implement a [`rotate_left`](#method.rotate_left) function,
+which may be what you want instead.
 
 # Examples
 
@@ -3542,8 +3644,8 @@ Note that this is *not* the same as a rotate-right; the
 RHS of a wrapping shift-right is restricted to the range
 of the type, rather than the bits shifted out of the LHS
 being returned to the other end. The primitive integer
-types all implement a `rotate_right` function, which may
-be what you want instead.
+types all implement a [`rotate_right`](#method.rotate_right) function,
+which may be what you want instead.
 
 # Examples
 
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 63a5277100f..e8483875c97 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -1357,6 +1357,15 @@ impl<'a, T> IntoIterator for &'a mut Option<T> {
 
 #[stable(since = "1.12.0", feature = "option_from")]
 impl<T> From<T> for Option<T> {
+    /// Copies `val` into a new `Some`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let o: Option<u8> = Option::from(67);
+    ///
+    /// assert_eq!(Some(67), o);
+    /// ```
     fn from(val: T) -> Option<T> {
         Some(val)
     }
@@ -1364,6 +1373,27 @@ impl<T> From<T> for Option<T> {
 
 #[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
 impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
+    /// Converts from `&Option<T>` to `Option<&T>`.
+    ///
+    /// # Examples
+    ///
+    /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original.
+    /// The [`map`] method takes the `self` argument by value, consuming the original,
+    /// so this technique uses `as_ref` to first take an `Option` to a reference
+    /// to the value inside the original.
+    ///
+    /// [`map`]: ../../std/option/enum.Option.html#method.map
+    /// [`String`]: ../../std/string/struct.String.html
+    /// [`usize`]: ../../std/primitive.usize.html
+    ///
+    /// ```
+    /// let s: Option<String> = Some(String::from("Hello, Rustaceans!"));
+    /// let o: Option<usize> = Option::from(&s).map(|ss: &String| ss.len());
+    ///
+    /// println!("Can still print s: {:?}", s);
+    ///
+    /// assert_eq!(o, Some(18));
+    /// ```
     fn from(o: &'a Option<T>) -> Option<&'a T> {
         o.as_ref()
     }
@@ -1371,6 +1401,21 @@ impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
 
 #[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
 impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
+    /// Converts from `&mut Option<T>` to `Option<&mut T>`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut s = Some(String::from("Hello"));
+    /// let o: Option<&mut String> = Option::from(&mut s);
+    ///
+    /// match o {
+    ///     Some(t) => *t = String::from("Hello, Rustaceans!"),
+    ///     None => (),
+    /// }
+    ///
+    /// assert_eq!(s, Some(String::from("Hello, Rustaceans!")));
+    /// ```
     fn from(o: &'a mut Option<T>) -> Option<&'a mut T> {
         o.as_mut()
     }
diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs
index 94ea9b78828..16739b4a1af 100644
--- a/src/libcore/panicking.rs
+++ b/src/libcore/panicking.rs
@@ -39,8 +39,12 @@ use crate::panic::{Location, PanicInfo};
 #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
 pub fn panic(expr: &str) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
+        // remove `unsafe` (and safety comment) on bootstrap bump
+        #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
         // SAFETY: the `abort` intrinsic has no requirements to be called.
-        unsafe { super::intrinsics::abort() }
+        unsafe {
+            super::intrinsics::abort()
+        }
     }
 
     // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
@@ -58,8 +62,12 @@ pub fn panic(expr: &str) -> ! {
 #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
 fn panic_bounds_check(index: usize, len: usize) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
+        // remove `unsafe` (and safety comment) on bootstrap bump
+        #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
         // SAFETY: the `abort` intrinsic has no requirements to be called.
-        unsafe { super::intrinsics::abort() }
+        unsafe {
+            super::intrinsics::abort()
+        }
     }
 
     panic!("index out of bounds: the len is {} but the index is {}", len, index)
@@ -72,8 +80,12 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 #[track_caller]
 pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
+        // remove `unsafe` (and safety comment) on bootstrap bump
+        #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
         // SAFETY: the `abort` intrinsic has no requirements to be called.
-        unsafe { super::intrinsics::abort() }
+        unsafe {
+            super::intrinsics::abort()
+        }
     }
 
     // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 58f779106f7..ecc70adda41 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -110,11 +110,17 @@ mod mut_ptr;
 ///   as the compiler doesn't need to prove that it's sound to elide the
 ///   copy.
 ///
+/// * It can be used to drop [pinned] data when `T` is not `repr(packed)`
+///   (pinned data must not be moved before it is dropped).
+///
 /// Unaligned values cannot be dropped in place, they must be copied to an aligned
-/// location first using [`ptr::read_unaligned`].
+/// location first using [`ptr::read_unaligned`]. For packed structs, this move is
+/// done automatically by the compiler. This means the fields of packed structs
+/// are not dropped in-place.
 ///
 /// [`ptr::read`]: ../ptr/fn.read.html
 /// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html
+/// [pinned]: ../pin/index.html
 ///
 /// # Safety
 ///
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index f74c6862006..3386f83ec81 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -3179,6 +3179,7 @@ macro_rules! is_empty {
         $self.ptr.as_ptr() as *const T == $self.end
     };
 }
+
 // To get rid of some bounds checks (see `position`), we compute the length in a somewhat
 // unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
 macro_rules! len {
@@ -3347,40 +3348,127 @@ macro_rules! iterator {
                 self.next_back()
             }
 
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn for_each<F>(mut self, mut f: F)
+            where
+                Self: Sized,
+                F: FnMut(Self::Item),
+            {
+                while let Some(x) = self.next() {
+                    f(x);
+                }
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn all<F>(&mut self, mut f: F) -> bool
+            where
+                Self: Sized,
+                F: FnMut(Self::Item) -> bool,
+            {
+                while let Some(x) = self.next() {
+                    if !f(x) {
+                        return false;
+                    }
+                }
+                true
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn any<F>(&mut self, mut f: F) -> bool
+            where
+                Self: Sized,
+                F: FnMut(Self::Item) -> bool,
+            {
+                while let Some(x) = self.next() {
+                    if f(x) {
+                        return true;
+                    }
+                }
+                false
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+            where
+                Self: Sized,
+                P: FnMut(&Self::Item) -> bool,
+            {
+                while let Some(x) = self.next() {
+                    if predicate(&x) {
+                        return Some(x);
+                    }
+                }
+                None
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile.
+            #[inline]
+            fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
+            where
+                Self: Sized,
+                F: FnMut(Self::Item) -> Option<B>,
+            {
+                while let Some(x) = self.next() {
+                    if let Some(y) = f(x) {
+                        return Some(y);
+                    }
+                }
+                None
+            }
+
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile. Also, the `assume` avoids a bounds check.
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
                 Self: Sized,
                 P: FnMut(Self::Item) -> bool,
             {
-                // The addition might panic on overflow.
                 let n = len!(self);
-                self.try_fold(0, move |i, x| {
-                    if predicate(x) { Err(i) }
-                    else { Ok(i + 1) }
-                }).err()
-                    .map(|i| {
+                let mut i = 0;
+                while let Some(x) = self.next() {
+                    if predicate(x) {
                         unsafe { assume(i < n) };
-                        i
-                    })
+                        return Some(i);
+                    }
+                    i += 1;
+                }
+                None
             }
 
+            // We override the default implementation, which uses `try_fold`,
+            // because this simple implementation generates less LLVM IR and is
+            // faster to compile. Also, the `assume` avoids a bounds check.
             #[inline]
             fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
                 P: FnMut(Self::Item) -> bool,
                 Self: Sized + ExactSizeIterator + DoubleEndedIterator
             {
-                // No need for an overflow check here, because `ExactSizeIterator`
                 let n = len!(self);
-                self.try_rfold(n, move |i, x| {
-                    let i = i - 1;
-                    if predicate(x) { Err(i) }
-                    else { Ok(i) }
-                }).err()
-                    .map(|i| {
+                let mut i = n;
+                while let Some(x) = self.next_back() {
+                    i -= 1;
+                    if predicate(x) {
                         unsafe { assume(i < n) };
-                        i
-                    })
+                        return Some(i);
+                    }
+                }
+                None
             }
 
             $($extra)*
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index 7da02b11676..52cf068f0a5 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -2140,6 +2140,24 @@ fn test_range_inclusive_nth_back() {
 }
 
 #[test]
+fn test_range_len() {
+    assert_eq!((0..10_u8).len(), 10);
+    assert_eq!((9..10_u8).len(), 1);
+    assert_eq!((10..10_u8).len(), 0);
+    assert_eq!((11..10_u8).len(), 0);
+    assert_eq!((100..10_u8).len(), 0);
+}
+
+#[test]
+fn test_range_inclusive_len() {
+    assert_eq!((0..=10_u8).len(), 11);
+    assert_eq!((9..=10_u8).len(), 2);
+    assert_eq!((10..=10_u8).len(), 1);
+    assert_eq!((11..=10_u8).len(), 0);
+    assert_eq!((100..=10_u8).len(), 0);
+}
+
+#[test]
 fn test_range_step() {
     #![allow(deprecated)]
 
@@ -2509,42 +2527,91 @@ fn test_chain_fold() {
 }
 
 #[test]
-fn test_step_replace_unsigned() {
-    let mut x = 4u32;
-    let y = x.replace_zero();
-    assert_eq!(x, 0);
-    assert_eq!(y, 4);
+fn test_steps_between() {
+    assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize));
+    assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize));
+    assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize));
+    assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize));
+    assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize));
+    assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize));
 
-    x = 5;
-    let y = x.replace_one();
-    assert_eq!(x, 1);
-    assert_eq!(y, 5);
+    // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms
+
+    assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize));
+    assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize));
+    if cfg!(target_pointer_width = "64") {
+        assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX));
+    }
+    assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None);
+    assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None);
+    assert_eq!(
+        Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,),
+        None,
+    );
 }
 
 #[test]
-fn test_step_replace_signed() {
-    let mut x = 4i32;
-    let y = x.replace_zero();
-    assert_eq!(x, 0);
-    assert_eq!(y, 4);
+fn test_step_forward() {
+    assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8));
+    assert_eq!(Step::forward_checked(252_u8, 200_usize), None);
+    assert_eq!(Step::forward_checked(0_u8, 256_usize), None);
+    assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8));
+    assert_eq!(Step::forward_checked(-110_i8, 248_usize), None);
+    assert_eq!(Step::forward_checked(-126_i8, 256_usize), None);
+
+    assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16));
+    assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX));
+    assert_eq!(Step::forward_checked(36_u16, 65500_usize), None);
+    assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16));
+    assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16));
+    assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None);
+    assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None);
 
-    x = 5;
-    let y = x.replace_one();
-    assert_eq!(x, 1);
-    assert_eq!(y, 5);
+    assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128));
+    assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128));
+    assert_eq!(
+        Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize),
+        Some(u128::MAX),
+    );
+    assert_eq!(
+        Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize),
+        None
+    );
+    assert_eq!(
+        Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize),
+        Some(i128::MAX),
+    );
+    assert_eq!(
+        Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
+        None
+    );
 }
 
 #[test]
-fn test_step_replace_no_between() {
-    let mut x = 4u128;
-    let y = x.replace_zero();
-    assert_eq!(x, 0);
-    assert_eq!(y, 4);
+fn test_step_backward() {
+    assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8));
+    assert_eq!(Step::backward_checked(100_u8, 200_usize), None);
+    assert_eq!(Step::backward_checked(255_u8, 256_usize), None);
+    assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8));
+    assert_eq!(Step::backward_checked(110_i8, 248_usize), None);
+    assert_eq!(Step::backward_checked(127_i8, 256_usize), None);
+
+    assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16));
+    assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16));
+    assert_eq!(Step::backward_checked(10_u16, 11_usize), None);
+    assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16));
+    assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16));
+    assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None);
+    assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None);
 
-    x = 5;
-    let y = x.replace_one();
-    assert_eq!(x, 1);
-    assert_eq!(y, 5);
+    assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128));
+    assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128));
+    assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128));
+    assert_eq!(Step::backward_checked(10_u128, 11_usize), None);
+    assert_eq!(
+        Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
+        Some(i128::MIN)
+    );
 }
 
 #[test]
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index e7d36d327cd..d636542d699 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -22,6 +22,7 @@
 #![feature(slice_partition_at_index)]
 #![feature(specialization)]
 #![feature(step_trait)]
+#![feature(step_trait_ext)]
 #![feature(str_internals)]
 #![feature(test)]
 #![feature(trusted_len)]
diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs
index 8d8276b4159..b1e87a7cac2 100644
--- a/src/libpanic_unwind/seh.rs
+++ b/src/libpanic_unwind/seh.rs
@@ -327,5 +327,8 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
 #[lang = "eh_personality"]
 #[cfg(not(test))]
 fn rust_eh_personality() {
-    unsafe { core::intrinsics::abort() }
+    #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
+    unsafe {
+        core::intrinsics::abort()
+    }
 }
diff --git a/src/libproc_macro/bridge/client.rs b/src/libproc_macro/bridge/client.rs
index d2222d12623..283aa25b0ea 100644
--- a/src/libproc_macro/bridge/client.rs
+++ b/src/libproc_macro/bridge/client.rs
@@ -202,10 +202,16 @@ impl Clone for Literal {
     }
 }
 
-// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
 impl fmt::Debug for Literal {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(&self.debug())
+        f.debug_struct("Literal")
+            // format the kind without quotes, as in `kind: Float`
+            .field("kind", &format_args!("{}", &self.debug_kind()))
+            .field("symbol", &self.symbol())
+            // format `Some("...")` on one line even in {:#?} mode
+            .field("suffix", &format_args!("{:?}", &self.suffix()))
+            .field("span", &self.span())
+            .finish()
     }
 }
 
diff --git a/src/libproc_macro/bridge/mod.rs b/src/libproc_macro/bridge/mod.rs
index a0e7d90f497..bf0d8fcee5b 100644
--- a/src/libproc_macro/bridge/mod.rs
+++ b/src/libproc_macro/bridge/mod.rs
@@ -103,8 +103,9 @@ macro_rules! with_api {
             Literal {
                 fn drop($self: $S::Literal);
                 fn clone($self: &$S::Literal) -> $S::Literal;
-                // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
-                fn debug($self: &$S::Literal) -> String;
+                fn debug_kind($self: &$S::Literal) -> String;
+                fn symbol($self: &$S::Literal) -> String;
+                fn suffix($self: &$S::Literal) -> Option<String>;
                 fn integer(n: &str) -> $S::Literal;
                 fn typed_integer(n: &str, kind: &str) -> $S::Literal;
                 fn float(n: &str) -> $S::Literal;
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 31bc61263ab..f11401b5a0c 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -158,6 +158,13 @@ impl fmt::Debug for TokenStream {
     }
 }
 
+#[stable(feature = "proc_macro_token_stream_default", since = "1.45.0")]
+impl Default for TokenStream {
+    fn default() -> Self {
+        TokenStream::new()
+    }
+}
+
 #[unstable(feature = "proc_macro_quote", issue = "54722")]
 pub use quote::{quote, quote_span};
 
@@ -1134,7 +1141,6 @@ impl fmt::Display for Literal {
 #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
 impl fmt::Debug for Literal {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
         self.0.fmt(f)
     }
 }
diff --git a/src/librustc_ast/util/literal.rs b/src/librustc_ast/util/literal.rs
index 1b17f343a6d..4428d09902b 100644
--- a/src/librustc_ast/util/literal.rs
+++ b/src/librustc_ast/util/literal.rs
@@ -6,8 +6,7 @@ use crate::tokenstream::TokenTree;
 
 use rustc_data_structures::sync::Lrc;
 use rustc_lexer::unescape::{unescape_byte, unescape_char};
-use rustc_lexer::unescape::{unescape_byte_str, unescape_str};
-use rustc_lexer::unescape::{unescape_raw_byte_str, unescape_raw_str};
+use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
@@ -59,45 +58,53 @@ impl LitKind {
                 // new symbol because the string in the LitKind is different to the
                 // string in the token.
                 let s = symbol.as_str();
-                let symbol = if s.contains(&['\\', '\r'][..]) {
-                    let mut buf = String::with_capacity(s.len());
-                    let mut error = Ok(());
-                    unescape_str(&s, &mut |_, unescaped_char| match unescaped_char {
-                        Ok(c) => buf.push(c),
-                        Err(_) => error = Err(LitError::LexerError),
-                    });
-                    error?;
-                    Symbol::intern(&buf)
-                } else {
-                    symbol
-                };
+                let symbol =
+                    if s.contains(&['\\', '\r'][..]) {
+                        let mut buf = String::with_capacity(s.len());
+                        let mut error = Ok(());
+                        unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
+                            match unescaped_char {
+                                Ok(c) => buf.push(c),
+                                Err(_) => error = Err(LitError::LexerError),
+                            }
+                        });
+                        error?;
+                        Symbol::intern(&buf)
+                    } else {
+                        symbol
+                    };
                 LitKind::Str(symbol, ast::StrStyle::Cooked)
             }
             token::StrRaw(n) => {
                 // Ditto.
                 let s = symbol.as_str();
-                let symbol = if s.contains('\r') {
-                    let mut buf = String::with_capacity(s.len());
-                    let mut error = Ok(());
-                    unescape_raw_str(&s, &mut |_, unescaped_char| match unescaped_char {
-                        Ok(c) => buf.push(c),
-                        Err(_) => error = Err(LitError::LexerError),
-                    });
-                    error?;
-                    buf.shrink_to_fit();
-                    Symbol::intern(&buf)
-                } else {
-                    symbol
-                };
+                let symbol =
+                    if s.contains('\r') {
+                        let mut buf = String::with_capacity(s.len());
+                        let mut error = Ok(());
+                        unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
+                            match unescaped_char {
+                                Ok(c) => buf.push(c),
+                                Err(_) => error = Err(LitError::LexerError),
+                            }
+                        });
+                        error?;
+                        buf.shrink_to_fit();
+                        Symbol::intern(&buf)
+                    } else {
+                        symbol
+                    };
                 LitKind::Str(symbol, ast::StrStyle::Raw(n))
             }
             token::ByteStr => {
                 let s = symbol.as_str();
                 let mut buf = Vec::with_capacity(s.len());
                 let mut error = Ok(());
-                unescape_byte_str(&s, &mut |_, unescaped_byte| match unescaped_byte {
-                    Ok(c) => buf.push(c),
-                    Err(_) => error = Err(LitError::LexerError),
+                unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
+                    match unescaped_byte {
+                        Ok(c) => buf.push(c),
+                        Err(_) => error = Err(LitError::LexerError),
+                    }
                 });
                 error?;
                 buf.shrink_to_fit();
@@ -108,9 +115,11 @@ impl LitKind {
                 let bytes = if s.contains('\r') {
                     let mut buf = Vec::with_capacity(s.len());
                     let mut error = Ok(());
-                    unescape_raw_byte_str(&s, &mut |_, unescaped_byte| match unescaped_byte {
-                        Ok(c) => buf.push(c),
-                        Err(_) => error = Err(LitError::LexerError),
+                    unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
+                        match unescaped_byte {
+                            Ok(c) => buf.push(c),
+                            Err(_) => error = Err(LitError::LexerError),
+                        }
                     });
                     error?;
                     buf.shrink_to_fit();
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 7e6dfbf00f5..2cf81af0416 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -33,7 +33,7 @@
 #![feature(array_value_iter)]
 #![feature(crate_visibility_modifier)]
 #![feature(marker_trait_attr)]
-#![feature(specialization)]
+#![feature(specialization)] // FIXME: min_specialization does not work
 #![feature(or_patterns)]
 #![recursion_limit = "256"]
 
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 46c415413e9..8eb125e4440 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -572,6 +572,35 @@ impl<'a> AstValidator<'a> {
             .emit();
     }
 
+    fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
+        if ident.name.as_str().is_ascii() {
+            return;
+        }
+        let head_span = self.session.source_map().guess_head_span(item_span);
+        struct_span_err!(
+            self.session,
+            head_span,
+            E0754,
+            "`#[no_mangle]` requires ASCII identifier"
+        )
+        .emit();
+    }
+
+    fn check_mod_file_item_asciionly(&self, ident: Ident) {
+        if ident.name.as_str().is_ascii() {
+            return;
+        }
+        struct_span_err!(
+            self.session,
+            ident.span,
+            E0754,
+            "trying to load file for module `{}` with non ascii identifer name",
+            ident.name
+        )
+        .help("consider using `#[path]` attribute to specify filesystem path")
+        .emit();
+    }
+
     fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
         if !generics.params.is_empty() {
             struct_span_err!(
@@ -866,6 +895,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             self.has_proc_macro_decls = true;
         }
 
+        if attr::contains_name(&item.attrs, sym::no_mangle) {
+            self.check_nomangle_item_asciionly(item.ident, item.span);
+        }
+
         match item.kind {
             ItemKind::Impl {
                 unsafety,
@@ -992,9 +1025,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
             }
-            ItemKind::Mod(_) => {
+            ItemKind::Mod(Mod { inline, .. }) => {
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                attr::first_attr_value_str_by_name(&item.attrs, sym::path);
+                if !inline && !attr::contains_name(&item.attrs, sym::path) {
+                    self.check_mod_file_item_asciionly(item.ident);
+                }
             }
             ItemKind::Union(ref vdata, _) => {
                 if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
diff --git a/src/librustc_ast_passes/node_count.rs b/src/librustc_ast_passes/node_count.rs
index 3cf562b927e..34db59b1b45 100644
--- a/src/librustc_ast_passes/node_count.rs
+++ b/src/librustc_ast_passes/node_count.rs
@@ -1,4 +1,4 @@
-// Simply gives a rought count of the number of nodes in an AST.
+// Simply gives a rough count of the number of nodes in an AST.
 
 use rustc_ast::ast::*;
 use rustc_ast::visit::*;
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index a592bbc2bf9..af09779d072 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -634,7 +634,7 @@ pub fn eval_condition(
                 [NestedMetaItem::Literal(Lit { span, .. })
                 | NestedMetaItem::MetaItem(MetaItem { span, .. })] => {
                     sess.span_diagnostic
-                        .struct_span_err(*span, &*format!("expected a version literal"))
+                        .struct_span_err(*span, "expected a version literal")
                         .emit();
                     return false;
                 }
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index dd9ada0b95d..a08235b304d 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -394,6 +394,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
         config.vectorize_slp,
         config.vectorize_loop,
         config.no_builtins,
+        config.emit_lifetime_markers,
         sanitizer_options.as_ref(),
         pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
         pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
@@ -934,10 +935,10 @@ pub unsafe fn with_llvm_pmb(
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
         }
         (llvm::CodeGenOptLevel::None, ..) => {
-            llvm::LLVMRustAddAlwaysInlinePass(builder, false);
+            llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
         }
         (llvm::CodeGenOptLevel::Less, ..) => {
-            llvm::LLVMRustAddAlwaysInlinePass(builder, true);
+            llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
         }
         (llvm::CodeGenOptLevel::Default, ..) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 89bd96c1fe2..f5ae9824df8 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -18,7 +18,6 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::config::{self, Sanitizer};
 use rustc_target::abi::{self, Align, Size};
 use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
@@ -1243,14 +1242,7 @@ impl Builder<'a, 'll, 'tcx> {
             return;
         }
 
-        let opts = &self.cx.sess().opts;
-        let emit = match opts.debugging_opts.sanitizer {
-            // Some sanitizer use lifetime intrinsics. When they are in use,
-            // emit lifetime intrinsics regardless of optimization level.
-            Some(Sanitizer::Address | Sanitizer::Memory) => true,
-            _ => opts.optimize != config::OptLevel::No,
-        };
-        if !emit {
+        if !self.cx().sess().emit_lifetime_markers() {
             return;
         }
 
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 0d466c2cd74..713cb2324f7 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -2000,6 +2000,7 @@ extern "C" {
         SLPVectorize: bool,
         LoopVectorize: bool,
         DisableSimplifyLibCalls: bool,
+        EmitLifetimeMarkers: bool,
         SanitizerOptions: Option<&SanitizerOptions>,
         PGOGenPath: *const c_char,
         PGOUsePath: *const c_char,
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index d8b38cf3370..ce158fb07da 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1179,6 +1179,28 @@ fn add_pre_link_args(
     cmd.args(&sess.opts.debugging_opts.pre_link_args);
 }
 
+/// Add a link script embedded in the target, if applicable.
+fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) {
+    match (crate_type, &sess.target.target.options.link_script) {
+        (CrateType::Cdylib | CrateType::Executable, Some(script)) => {
+            if !sess.target.target.options.linker_is_gnu {
+                sess.fatal("can only use link script when linking with GNU-like linker");
+            }
+
+            let file_name = ["rustc", &sess.target.target.llvm_target, "linkfile.ld"].join("-");
+
+            let path = tmpdir.join(file_name);
+            if let Err(e) = fs::write(&path, script) {
+                sess.fatal(&format!("failed to write link script to {}: {}", path.display(), e));
+            }
+
+            cmd.arg("--script");
+            cmd.arg(path);
+        }
+        _ => {}
+    }
+}
+
 /// Add arbitrary "user defined" args defined from command line and by `#[link_args]` attributes.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_user_defined_link_args(
@@ -1421,8 +1443,11 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
     add_pre_link_args(cmd, sess, flavor, crate_type);
 
+    // NO-OPT-OUT
+    add_link_script(cmd, sess, tmpdir, crate_type);
+
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.target.options.is_like_fuchsia {
+    if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
         let prefix = match sess.opts.debugging_opts.sanitizer {
             Some(Sanitizer::Address) => "asan/",
             _ => "",
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 6210559251d..53dfe7cb749 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -21,7 +21,7 @@ use rustc_errors::{DiagnosticId, FatalError, Handler, Level};
 use rustc_fs_util::link_or_copy;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_incremental::{
-    copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
+    copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
 };
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::EncodedMetadata;
@@ -110,6 +110,7 @@ pub struct ModuleConfig {
     pub merge_functions: bool,
     pub inline_threshold: Option<usize>,
     pub new_llvm_pass_manager: bool,
+    pub emit_lifetime_markers: bool,
 }
 
 impl ModuleConfig {
@@ -244,6 +245,7 @@ impl ModuleConfig {
 
             inline_threshold: sess.opts.cg.inline_threshold,
             new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager,
+            emit_lifetime_markers: sess.emit_lifetime_markers(),
         }
     }
 
@@ -465,17 +467,13 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
         return work_products;
     }
 
-    let _timer = sess.timer("incr_comp_copy_cgu_workproducts");
+    let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
 
     for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
-        let mut files = vec![];
-
-        if let Some(ref path) = module.object {
-            files.push(path.clone());
-        }
+        let path = module.object.as_ref().map(|path| path.clone());
 
         if let Some((id, product)) =
-            copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files)
+            copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, &path)
         {
             work_products.insert(id, product);
         }
@@ -817,7 +815,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
 ) -> Result<WorkItemResult<B>, FatalError> {
     let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
     let mut object = None;
-    for saved_file in &module.source.saved_files {
+    if let Some(saved_file) = module.source.saved_file {
         let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name));
         object = Some(obj_out.clone());
         let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs
index 6c0e4128e30..1d8730db546 100644
--- a/src/librustc_codegen_ssa/debuginfo/type_names.rs
+++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs
@@ -198,7 +198,6 @@ pub fn push_debuginfo_type_name<'tcx>(
         ty::Error
         | ty::Infer(_)
         | ty::Placeholder(..)
-        | ty::UnnormalizedProjection(..)
         | ty::Projection(..)
         | ty::Bound(..)
         | ty::Opaque(..)
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index f543f8051a4..81ad032967b 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -28,7 +28,7 @@ rustc_index = { path = "../librustc_index", package = "rustc_index" }
 bitflags = "1.2.1"
 measureme = "0.7.1"
 libc = "0.2"
-stacker = "0.1.6"
+stacker = "0.1.9"
 
 [dependencies.parking_lot]
 version = "0.10"
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 9164734783c..7ee60176dbe 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -12,7 +12,7 @@
 #![feature(generators)]
 #![feature(generator_trait)]
 #![feature(fn_traits)]
-#![feature(specialization)]
+#![feature(min_specialization)]
 #![feature(optin_builtin_traits)]
 #![feature(nll)]
 #![feature(allow_internal_unstable)]
diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs
index 78cbc1240b1..e94a0c6eb59 100644
--- a/src/librustc_data_structures/tiny_list.rs
+++ b/src/librustc_data_structures/tiny_list.rs
@@ -52,7 +52,7 @@ impl<T: PartialEq> TinyList<T> {
             if &e.data == data {
                 return true;
             }
-            elem = e.next.as_ref().map(|e| &**e);
+            elem = e.next.as_deref();
         }
         false
     }
@@ -62,7 +62,7 @@ impl<T: PartialEq> TinyList<T> {
         let (mut elem, mut count) = (self.head.as_ref(), 0);
         while let Some(ref e) = elem {
             count += 1;
-            elem = e.next.as_ref().map(|e| &**e);
+            elem = e.next.as_deref();
         }
         count
     }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 913ccf8e680..6847b175e60 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -1138,6 +1138,16 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported>
     })
 }
 
+/// Variant of `catch_fatal_errors` for the `interface::Result` return type
+/// that also computes the exit code.
+pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
+    let result = catch_fatal_errors(f).and_then(|result| result);
+    match result {
+        Ok(()) => EXIT_SUCCESS,
+        Err(_) => EXIT_FAILURE,
+    }
+}
+
 lazy_static! {
     static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
         let hook = panic::take_hook();
@@ -1228,12 +1238,12 @@ pub fn init_rustc_env_logger() {
     env_logger::init_from_env("RUSTC_LOG");
 }
 
-pub fn main() {
+pub fn main() -> ! {
     let start = Instant::now();
     init_rustc_env_logger();
     let mut callbacks = TimePassesCallbacks::default();
     install_ice_hook();
-    let result = catch_fatal_errors(|| {
+    let exit_code = catch_with_exit_code(|| {
         let args = env::args_os()
             .enumerate()
             .map(|(i, arg)| {
@@ -1246,13 +1256,8 @@ pub fn main() {
             })
             .collect::<Vec<_>>();
         run_compiler(&args, &mut callbacks, None, None)
-    })
-    .and_then(|result| result);
-    let exit_code = match result {
-        Ok(_) => EXIT_SUCCESS,
-        Err(_) => EXIT_FAILURE,
-    };
+    });
     // The extra `\t` is necessary to align this label with the others.
     print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
-    process::exit(exit_code);
+    process::exit(exit_code)
 }
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 6467561e509..c0b16c22e4d 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -120,6 +120,7 @@ E0223: include_str!("./error_codes/E0223.md"),
 E0224: include_str!("./error_codes/E0224.md"),
 E0225: include_str!("./error_codes/E0225.md"),
 E0226: include_str!("./error_codes/E0226.md"),
+E0228: include_str!("./error_codes/E0228.md"),
 E0229: include_str!("./error_codes/E0229.md"),
 E0230: include_str!("./error_codes/E0230.md"),
 E0231: include_str!("./error_codes/E0231.md"),
@@ -435,6 +436,7 @@ E0750: include_str!("./error_codes/E0750.md"),
 E0751: include_str!("./error_codes/E0751.md"),
 E0752: include_str!("./error_codes/E0752.md"),
 E0753: include_str!("./error_codes/E0753.md"),
+E0754: include_str!("./error_codes/E0754.md"),
 E0755: include_str!("./error_codes/E0755.md"),
 ;
 //  E0006, // merged with E0005
@@ -483,7 +485,6 @@ E0755: include_str!("./error_codes/E0755.md"),
 //  E0218, // no associated type defined
 //  E0219, // associated type defined in higher-ranked supertrait
     E0227, // ambiguous lifetime bound, explicit lifetime bound required
-    E0228, // explicit lifetime bound required
 //  E0233,
 //  E0234,
 //  E0235, // structure constructor specifies a structure of type but
diff --git a/src/librustc_error_codes/error_codes/E0228.md b/src/librustc_error_codes/error_codes/E0228.md
new file mode 100644
index 00000000000..3443a5ae863
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0228.md
@@ -0,0 +1,40 @@
+The lifetime bound for this object type cannot be deduced from context and must
+be specified.
+
+Erroneous code example:
+
+```compile_fail,E0228
+trait Trait { }
+
+struct TwoBounds<'a, 'b, T: Sized + 'a + 'b> {
+    x: &'a i32,
+    y: &'b i32,
+    z: T,
+}
+
+type Foo<'a, 'b> = TwoBounds<'a, 'b, dyn Trait>;
+```
+
+When a trait object is used as a type argument of a generic type, Rust will try
+to infer its lifetime if unspecified. However, this isn't possible when the
+containing type has more than one lifetime bound.
+
+The above example can be resolved by either reducing the number of lifetime
+bounds to one or by making the trait object lifetime explicit, like so:
+
+```
+trait Trait { }
+
+struct TwoBounds<'a, 'b, T: Sized + 'a + 'b> {
+    x: &'a i32,
+    y: &'b i32,
+    z: T,
+}
+
+type Foo<'a, 'b> = TwoBounds<'a, 'b, dyn Trait + 'b>;
+```
+
+For more information, see [RFC 599] and its amendment [RFC 1156].
+
+[RFC 599]: https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md
+[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md
diff --git a/src/librustc_error_codes/error_codes/E0307.md b/src/librustc_error_codes/error_codes/E0307.md
index 52707b93acc..0d29d56ea1a 100644
--- a/src/librustc_error_codes/error_codes/E0307.md
+++ b/src/librustc_error_codes/error_codes/E0307.md
@@ -64,7 +64,7 @@ impl Trait for Foo {
 }
 ```
 
-The nightly feature [Arbintrary self types][AST] extends the accepted
+The nightly feature [Arbitrary self types][AST] extends the accepted
 set of receiver types to also include any type that can dereference to
 `Self`:
 
diff --git a/src/librustc_error_codes/error_codes/E0571.md b/src/librustc_error_codes/error_codes/E0571.md
index c2a3a8d7588..eadae05aa30 100644
--- a/src/librustc_error_codes/error_codes/E0571.md
+++ b/src/librustc_error_codes/error_codes/E0571.md
@@ -7,7 +7,7 @@ Example of erroneous code:
 # fn satisfied(n: usize) -> bool { n % 23 == 0 }
 let result = while true {
     if satisfied(i) {
-        break 2*i; // error: `break` with value from a `while` loop
+        break 2 * i; // error: `break` with value from a `while` loop
     }
     i += 1;
 };
@@ -22,9 +22,9 @@ Make sure `break value;` statements only occur in `loop` loops:
 ```
 # let mut i = 1;
 # fn satisfied(n: usize) -> bool { n % 23 == 0 }
-let result = loop { // ok!
+let result = loop { // This is now a "loop" loop.
     if satisfied(i) {
-        break 2*i;
+        break 2 * i; // ok!
     }
     i += 1;
 };
diff --git a/src/librustc_error_codes/error_codes/E0579.md b/src/librustc_error_codes/error_codes/E0579.md
index 225e27f0cab..f554242a3d4 100644
--- a/src/librustc_error_codes/error_codes/E0579.md
+++ b/src/librustc_error_codes/error_codes/E0579.md
@@ -1,7 +1,4 @@
-When matching against an exclusive range, the compiler verifies that the range
-is non-empty. Exclusive range patterns include the start point but not the end
-point, so this is equivalent to requiring the start of the range to be less
-than the end of the range.
+A lower range wasn't less than the upper range.
 
 Erroneous code example:
 
@@ -17,3 +14,8 @@ fn main() {
     }
 }
 ```
+
+When matching against an exclusive range, the compiler verifies that the range
+is non-empty. Exclusive range patterns include the start point but not the end
+point, so this is equivalent to requiring the start of the range to be less
+than the end of the range.
diff --git a/src/librustc_error_codes/error_codes/E0581.md b/src/librustc_error_codes/error_codes/E0581.md
index 947ec255a9d..89f6e3269ec 100644
--- a/src/librustc_error_codes/error_codes/E0581.md
+++ b/src/librustc_error_codes/error_codes/E0581.md
@@ -1,4 +1,4 @@
-In a `fn` type, a lifetime appears only in the return type,
+In a `fn` type, a lifetime appears only in the return type
 and not in the arguments types.
 
 Erroneous code example:
@@ -10,8 +10,11 @@ fn main() {
 }
 ```
 
-To fix this issue, either use the lifetime in the arguments, or use
-`'static`. Example:
+The problem here is that the lifetime isn't contrained by any of the arguments,
+making it impossible to determine how long it's supposed to live.
+
+To fix this issue, either use the lifetime in the arguments, or use the
+`'static` lifetime. Example:
 
 ```
 fn main() {
diff --git a/src/librustc_error_codes/error_codes/E0582.md b/src/librustc_error_codes/error_codes/E0582.md
index c0cf44852c4..e50cc60ea33 100644
--- a/src/librustc_error_codes/error_codes/E0582.md
+++ b/src/librustc_error_codes/error_codes/E0582.md
@@ -1,5 +1,5 @@
-A lifetime appears only in an associated-type binding,
-and not in the input types to the trait.
+A lifetime is only present in an associated-type binding, and not in the input
+types to the trait.
 
 Erroneous code example:
 
diff --git a/src/librustc_error_codes/error_codes/E0589.md b/src/librustc_error_codes/error_codes/E0589.md
index 5e15a875b0b..8a4f8d21725 100644
--- a/src/librustc_error_codes/error_codes/E0589.md
+++ b/src/librustc_error_codes/error_codes/E0589.md
@@ -1,6 +1,8 @@
 The value of `N` that was specified for `repr(align(N))` was not a power
 of two, or was greater than 2^29.
 
+Erroneous code example:
+
 ```compile_fail,E0589
 #[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two
 enum Foo {
diff --git a/src/librustc_error_codes/error_codes/E0754.md b/src/librustc_error_codes/error_codes/E0754.md
new file mode 100644
index 00000000000..abdc01ed21a
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0754.md
@@ -0,0 +1,33 @@
+An non-ascii identifier was used in an invalid context.
+
+Erroneous code example:
+
+```compile_fail,E0754
+# #![feature(non_ascii_idents)]
+
+mod řųśť;
+// ^ error!
+fn main() {}
+```
+
+```compile_fail,E0754
+# #![feature(non_ascii_idents)]
+
+#[no_mangle]
+fn řųśť() {}
+// ^ error!
+fn main() {}
+```
+
+Non-ascii can be used as module names if it is inline
+or a #\[path\] attribute is specified. For example:
+
+```
+# #![feature(non_ascii_idents)]
+
+mod řųśť {
+    const IS_GREAT: bool = true;
+}
+
+fn main() {}
+```
diff --git a/src/librustc_error_codes/error_codes/E0755.md b/src/librustc_error_codes/error_codes/E0755.md
index b6eb2e34ccf..0c289146176 100644
--- a/src/librustc_error_codes/error_codes/E0755.md
+++ b/src/librustc_error_codes/error_codes/E0755.md
@@ -3,7 +3,7 @@ or `Self` that references lifetimes from a parent scope.
 
 Erroneous code example:
 
-```compile_fail,E0754,edition2018
+```compile_fail,E0755,edition2018
 struct S<'a>(&'a i32);
 
 impl<'a> S<'a> {
diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs
index 2cb6267e0f6..2932475430b 100644
--- a/src/librustc_expand/parse/lexer/tests.rs
+++ b/src/librustc_expand/parse/lexer/tests.rs
@@ -50,13 +50,13 @@ fn t1() {
         assert_eq!(string_reader.next_token(), token::Whitespace);
         // Read another token.
         let tok3 = string_reader.next_token();
-        assert_eq!(string_reader.pos.clone(), BytePos(28));
+        assert_eq!(string_reader.pos(), BytePos(28));
         let tok4 = Token::new(mk_ident("main"), Span::with_root_ctxt(BytePos(24), BytePos(28)));
         assert_eq!(tok3.kind, tok4.kind);
         assert_eq!(tok3.span, tok4.span);
 
         assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren));
-        assert_eq!(string_reader.pos.clone(), BytePos(29))
+        assert_eq!(string_reader.pos(), BytePos(29))
     })
 }
 
diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs
index afc6dc36eb4..b9693c2c862 100644
--- a/src/librustc_expand/proc_macro_server.rs
+++ b/src/librustc_expand/proc_macro_server.rs
@@ -507,9 +507,14 @@ impl server::Ident for Rustc<'_> {
 }
 
 impl server::Literal for Rustc<'_> {
-    // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
-    fn debug(&mut self, literal: &Self::Literal) -> String {
-        format!("{:?}", literal)
+    fn debug_kind(&mut self, literal: &Self::Literal) -> String {
+        format!("{:?}", literal.lit.kind)
+    }
+    fn symbol(&mut self, literal: &Self::Literal) -> String {
+        literal.lit.symbol.to_string()
+    }
+    fn suffix(&mut self, literal: &Self::Literal) -> Option<String> {
+        literal.lit.suffix.as_ref().map(Symbol::to_string)
     }
     fn integer(&mut self, n: &str) -> Self::Literal {
         self.lit(token::Integer, Symbol::intern(n), None)
diff --git a/src/librustc_hir/lib.rs b/src/librustc_hir/lib.rs
index 49692c73fad..b51c0a6e988 100644
--- a/src/librustc_hir/lib.rs
+++ b/src/librustc_hir/lib.rs
@@ -8,7 +8,7 @@
 #![feature(const_panic)]
 #![feature(in_band_lifetimes)]
 #![feature(or_patterns)]
-#![feature(specialization)]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index dd715c6c81d..7fd4b3c2554 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -15,7 +15,7 @@ pub mod assert_module_sources;
 mod persist;
 
 pub use assert_dep_graph::assert_dep_graph;
-pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
+pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
 pub use persist::delete_workproduct_files;
 pub use persist::dep_graph_tcx_init;
 pub use persist::finalize_session_directory;
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index 99c799950c0..966faa9639d 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -134,7 +134,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
 
             for swp in work_products {
                 let mut all_files_exist = true;
-                for file_name in swp.work_product.saved_files.iter() {
+                if let Some(ref file_name) = swp.work_product.saved_file {
                     let path = in_incr_comp_dir_sess(sess, file_name);
                     if !path.exists() {
                         all_files_exist = false;
diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs
index 6a03a01430b..7bc3b47e15a 100644
--- a/src/librustc_incremental/persist/mod.rs
+++ b/src/librustc_incremental/persist/mod.rs
@@ -21,5 +21,5 @@ pub use load::LoadResult;
 pub use load::{load_dep_graph, DepGraphFuture};
 pub use save::save_dep_graph;
 pub use save::save_work_product_index;
-pub use work_product::copy_cgu_workproducts_to_incr_comp_cache_dir;
+pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
 pub use work_product::delete_workproduct_files;
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 4db6297712c..c43d4ad4049 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -74,9 +74,9 @@ pub fn save_work_product_index(
         if !new_work_products.contains_key(id) {
             work_product::delete_workproduct_files(sess, wp);
             debug_assert!(
-                wp.saved_files
-                    .iter()
-                    .all(|file_name| { !in_incr_comp_dir_sess(sess, file_name).exists() })
+                wp.saved_file.as_ref().map_or(true, |file_name| {
+                    !in_incr_comp_dir_sess(sess, &file_name).exists()
+                })
             );
         }
     }
@@ -85,7 +85,7 @@ pub fn save_work_product_index(
     debug_assert!({
         new_work_products
             .iter()
-            .flat_map(|(_, wp)| wp.saved_files.iter())
+            .flat_map(|(_, wp)| wp.saved_file.iter())
             .map(|name| in_incr_comp_dir_sess(sess, name))
             .all(|path| path.exists())
     });
diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs
index a15ee6d81db..19d64bda56d 100644
--- a/src/librustc_incremental/persist/work_product.rs
+++ b/src/librustc_incremental/persist/work_product.rs
@@ -7,43 +7,41 @@ use rustc_session::Session;
 use std::fs as std_fs;
 use std::path::PathBuf;
 
-pub fn copy_cgu_workproducts_to_incr_comp_cache_dir(
+pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
     sess: &Session,
     cgu_name: &str,
-    files: &[PathBuf],
+    path: &Option<PathBuf>,
 ) -> Option<(WorkProductId, WorkProduct)> {
-    debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})", cgu_name, files);
+    debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path);
     sess.opts.incremental.as_ref()?;
 
-    let saved_files = files
-        .iter()
-        .map(|path| {
-            let file_name = format!("{}.o", cgu_name);
-            let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
-            match link_or_copy(path, &path_in_incr_dir) {
-                Ok(_) => Some(file_name),
-                Err(err) => {
-                    sess.warn(&format!(
-                        "error copying object file `{}` \
-                                             to incremental directory as `{}`: {}",
-                        path.display(),
-                        path_in_incr_dir.display(),
-                        err
-                    ));
-                    None
-                }
+    let saved_file = if let Some(path) = path {
+        let file_name = format!("{}.o", cgu_name);
+        let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
+        match link_or_copy(path, &path_in_incr_dir) {
+            Ok(_) => Some(file_name),
+            Err(err) => {
+                sess.warn(&format!(
+                    "error copying object file `{}` to incremental directory as `{}`: {}",
+                    path.display(),
+                    path_in_incr_dir.display(),
+                    err
+                ));
+                return None;
             }
-        })
-        .collect::<Option<Vec<_>>>()?;
+        }
+    } else {
+        None
+    };
 
-    let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_files };
+    let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file };
 
     let work_product_id = WorkProductId::from_cgu_name(cgu_name);
     Some((work_product_id, work_product))
 }
 
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
-    for file_name in &work_product.saved_files {
+    if let Some(ref file_name) = work_product.saved_file {
         let path = in_incr_comp_dir_sess(sess, file_name);
         match std_fs::remove_file(&path) {
             Ok(()) => {}
diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs
index a84f89c7cd9..67dcea58cf8 100644
--- a/src/librustc_index/vec.rs
+++ b/src/librustc_index/vec.rs
@@ -65,7 +65,7 @@ impl Idx for u32 {
 /// `u32::MAX`. You can also customize things like the `Debug` impl,
 /// what traits are derived, and so forth via the macro.
 #[macro_export]
-#[allow_internal_unstable(step_trait, rustc_attrs)]
+#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
 macro_rules! newtype_index {
     // ---- public rules ----
 
@@ -181,7 +181,7 @@ macro_rules! newtype_index {
             }
         }
 
-        impl ::std::iter::Step for $type {
+        unsafe impl ::std::iter::Step for $type {
             #[inline]
             fn steps_between(start: &Self, end: &Self) -> Option<usize> {
                 <usize as ::std::iter::Step>::steps_between(
@@ -191,33 +191,13 @@ macro_rules! newtype_index {
             }
 
             #[inline]
-            fn replace_one(&mut self) -> Self {
-                ::std::mem::replace(self, Self::from_u32(1))
+            fn forward_checked(start: Self, u: usize) -> Option<Self> {
+                Self::index(start).checked_add(u).map(Self::from_usize)
             }
 
             #[inline]
-            fn replace_zero(&mut self) -> Self {
-                ::std::mem::replace(self, Self::from_u32(0))
-            }
-
-            #[inline]
-            fn add_one(&self) -> Self {
-                Self::from_usize(Self::index(*self) + 1)
-            }
-
-            #[inline]
-            fn sub_one(&self) -> Self {
-                Self::from_usize(Self::index(*self) - 1)
-            }
-
-            #[inline]
-            fn add_usize(&self, u: usize) -> Option<Self> {
-                Self::index(*self).checked_add(u).map(Self::from_usize)
-            }
-
-            #[inline]
-            fn sub_usize(&self, u: usize) -> Option<Self> {
-                Self::index(*self).checked_sub(u).map(Self::from_usize)
+            fn backward_checked(start: Self, u: usize) -> Option<Self> {
+                Self::index(start).checked_sub(u).map(Self::from_usize)
             }
         }
 
diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs
index a0b5dd45a0e..5551b56ab79 100644
--- a/src/librustc_infer/infer/canonical/canonicalizer.rs
+++ b/src/librustc_infer/infer/canonical/canonicalizer.rs
@@ -415,7 +415,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
             | ty::Never
             | ty::Tuple(..)
             | ty::Projection(..)
-            | ty::UnnormalizedProjection(..)
             | ty::Foreign(..)
             | ty::Param(..)
             | ty::Opaque(..) => {
diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index d8133c58df7..0141ba82737 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -554,7 +554,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     let output = bound_output.skip_binder();
                     err.span_label(e.span, &format!("this method call resolves to `{:?}`", output));
                     let kind = &output.kind;
-                    if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind {
+                    if let ty::Projection(proj) = kind {
                         if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
                             err.span_label(span, &format!("`{:?}` defined here", output));
                         }
diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs
index 47346c3a856..c9ed687eaf2 100644
--- a/src/librustc_infer/infer/freshen.rs
+++ b/src/librustc_infer/infer/freshen.rs
@@ -204,7 +204,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             | ty::Never
             | ty::Tuple(..)
             | ty::Projection(..)
-            | ty::UnnormalizedProjection(..)
             | ty::Foreign(..)
             | ty::Param(..)
             | ty::Closure(..)
diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
index 3ff0e26a4dc..33a80fb7471 100644
--- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
@@ -325,8 +325,21 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
             }
         }
 
-        debug!("enforce_member_constraint: final least choice = {:?}", least_choice);
-        if least_choice != member_lower_bound {
+        // (#72087) Different `ty::Regions` can be known to be equal, for
+        // example, we know that `'a` and `'static` are equal in a function
+        // with a parameter of type `&'static &'a ()`.
+        //
+        // When we have two equal regions like this `expansion` will use
+        // `lub_concrete_regions` to pick a canonical representative. The same
+        // choice is needed here so that we don't end up in a cycle of
+        // `expansion` changing the region one way and the code here changing
+        // it back.
+        let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
+        debug!(
+            "enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
+            least_choice, lub
+        );
+        if lub != member_lower_bound {
             *var_values.value_mut(member_vid) = VarValue::Value(least_choice);
             true
         } else {
@@ -578,8 +591,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 self.tcx().mk_region(ReScope(lub))
             }
 
-            (&ReEarlyBound(_), &ReEarlyBound(_) | &ReFree(_))
-            | (&ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => {
+            (&ReEarlyBound(_) | &ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => {
                 self.region_rels.lub_free_regions(a, b)
             }
 
diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs
index 55bea57f3e2..b34685006e2 100644
--- a/src/librustc_infer/traits/util.rs
+++ b/src/librustc_infer/traits/util.rs
@@ -112,8 +112,7 @@ pub fn elaborate_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
 ) -> Elaborator<'tcx> {
-    let obligations =
-        predicates.into_iter().map(|predicate| predicate_obligation(predicate, None)).collect();
+    let obligations = predicates.map(|predicate| predicate_obligation(predicate, None)).collect();
     elaborate_obligations(tcx, obligations)
 }
 
@@ -149,7 +148,7 @@ impl Elaborator<'tcx> {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
-                let obligations = predicates.predicates.into_iter().map(|(pred, span)| {
+                let obligations = predicates.predicates.iter().map(|(pred, span)| {
                     predicate_obligation(
                         pred.subst_supertrait(tcx, &data.to_poly_trait_ref()),
                         Some(*span),
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index 9e8f3a84e20..94cd4bcd4c6 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -137,7 +137,7 @@ impl<'tcx> Queries<'tcx> {
             let result = passes::register_plugins(
                 self.session(),
                 &*self.codegen_backend().metadata_loader(),
-                self.compiler.register_lints.as_ref().map(|p| &**p).unwrap_or_else(|| empty),
+                self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
                 krate,
                 &crate_name,
             );
diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs
index 5ccfc1b276b..e44feee9660 100644
--- a/src/librustc_lexer/src/lib.rs
+++ b/src/librustc_lexer/src/lib.rs
@@ -1,5 +1,11 @@
 //! Low-level Rust lexer.
 //!
+//! The idea with `librustc_lexer` is to make a reusable library,
+//! by separating out pure lexing and rustc-specific concerns, like spans,
+//! error reporting an interning.  So, rustc_lexer operates directly on `&str`,
+//! produces simple tokens which are a pair of type-tag and a bit of original text,
+//! and does not report errors, instead storing them as flags on the token.
+//!
 //! Tokens produced by this lexer are not yet ready for parsing the Rust syntax,
 //! for that see `librustc_parse::lexer`, which converts this basic token stream
 //! into wide tokens used by actual parser.
@@ -719,6 +725,9 @@ impl Cursor<'_> {
 
             // Check that amount of closing '#' symbols
             // is equal to the amount of opening ones.
+            // Note that this will not consume extra trailing `#` characters:
+            // `r###"abcde"####` is lexed as a `LexedRawString { n_hashes: 3 }`
+            // followed by a `#` token.
             let mut hashes_left = n_start_hashes;
             let is_closing_hash = |c| {
                 if c == '#' && hashes_left != 0 {
@@ -739,8 +748,8 @@ impl Cursor<'_> {
                     possible_terminator_offset: None,
                 };
             } else if n_end_hashes > max_hashes {
-                // Keep track of possible terminators to give a hint about where there might be
-                // a missing terminator
+                // Keep track of possible terminators to give a hint about
+                // where there might be a missing terminator
                 possible_terminator_offset =
                     Some(self.len_consumed() - start_pos - n_end_hashes + prefix_len);
                 max_hashes = n_end_hashes;
diff --git a/src/librustc_lexer/src/unescape.rs b/src/librustc_lexer/src/unescape.rs
index c51bf735fa7..2a9e1b7cbc3 100644
--- a/src/librustc_lexer/src/unescape.rs
+++ b/src/librustc_lexer/src/unescape.rs
@@ -58,69 +58,57 @@ pub enum EscapeError {
     NonAsciiCharInByteString,
 }
 
-/// Takes a contents of a char literal (without quotes), and returns an
-/// unescaped char or an error
-pub fn unescape_char(literal_text: &str) -> Result<char, (usize, EscapeError)> {
-    let mut chars = literal_text.chars();
-    unescape_char_or_byte(&mut chars, Mode::Char)
-        .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
-}
-
-/// Takes a contents of a byte literal (without quotes), and returns an
-/// unescaped byte or an error.
-pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
-    let mut chars = literal_text.chars();
-    unescape_char_or_byte(&mut chars, Mode::Byte)
-        .map(byte_from_char)
-        .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
-}
-
-/// Takes a contents of a string literal (without quotes) and produces a
+/// Takes a contents of a literal (without quotes) and produces a
 /// sequence of escaped characters or errors.
 /// Values are returned through invoking of the provided callback.
-pub fn unescape_str<F>(literal_text: &str, callback: &mut F)
+pub fn unescape_literal<F>(literal_text: &str, mode: Mode, callback: &mut F)
 where
     F: FnMut(Range<usize>, Result<char, EscapeError>),
 {
-    unescape_str_or_byte_str(literal_text, Mode::Str, callback)
+    match mode {
+        Mode::Char | Mode::Byte => {
+            let mut chars = literal_text.chars();
+            let result = unescape_char_or_byte(&mut chars, mode);
+            // The Chars iterator moved forward.
+            callback(0..(literal_text.len() - chars.as_str().len()), result);
+        }
+        Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(literal_text, mode, callback),
+        // NOTE: Raw strings do not perform any explicit character escaping, here we
+        // only translate CRLF to LF and produce errors on bare CR.
+        Mode::RawStr | Mode::RawByteStr => {
+            unescape_raw_str_or_byte_str(literal_text, mode, callback)
+        }
+    }
 }
 
-/// Takes a contents of a byte string literal (without quotes) and produces a
-/// sequence of bytes or errors.
+/// Takes a contents of a byte, byte string or raw byte string (without quotes)
+/// and produces a sequence of bytes or errors.
 /// Values are returned through invoking of the provided callback.
-pub fn unescape_byte_str<F>(literal_text: &str, callback: &mut F)
+pub fn unescape_byte_literal<F>(literal_text: &str, mode: Mode, callback: &mut F)
 where
     F: FnMut(Range<usize>, Result<u8, EscapeError>),
 {
-    unescape_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
-        callback(range, char.map(byte_from_char))
+    assert!(mode.is_bytes());
+    unescape_literal(literal_text, mode, &mut |range, result| {
+        callback(range, result.map(byte_from_char));
     })
 }
 
-/// Takes a contents of a raw string literal (without quotes) and produces a
-/// sequence of characters or errors.
-/// Values are returned through invoking of the provided callback.
-/// NOTE: Raw strings do not perform any explicit character escaping, here we
-/// only translate CRLF to LF and produce errors on bare CR.
-pub fn unescape_raw_str<F>(literal_text: &str, callback: &mut F)
-where
-    F: FnMut(Range<usize>, Result<char, EscapeError>),
-{
-    unescape_raw_str_or_byte_str(literal_text, Mode::Str, callback)
+/// Takes a contents of a char literal (without quotes), and returns an
+/// unescaped char or an error
+pub fn unescape_char(literal_text: &str) -> Result<char, (usize, EscapeError)> {
+    let mut chars = literal_text.chars();
+    unescape_char_or_byte(&mut chars, Mode::Char)
+        .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
 }
 
-/// Takes a contents of a raw byte string literal (without quotes) and produces a
-/// sequence of bytes or errors.
-/// Values are returned through invoking of the provided callback.
-/// NOTE: Raw strings do not perform any explicit character escaping, here we
-/// only translate CRLF to LF and produce errors on bare CR.
-pub fn unescape_raw_byte_str<F>(literal_text: &str, callback: &mut F)
-where
-    F: FnMut(Range<usize>, Result<u8, EscapeError>),
-{
-    unescape_raw_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
-        callback(range, char.map(byte_from_char))
-    })
+/// Takes a contents of a byte literal (without quotes), and returns an
+/// unescaped byte or an error.
+pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
+    let mut chars = literal_text.chars();
+    unescape_char_or_byte(&mut chars, Mode::Byte)
+        .map(byte_from_char)
+        .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
 }
 
 /// What kind of literal do we parse.
@@ -130,13 +118,15 @@ pub enum Mode {
     Str,
     Byte,
     ByteStr,
+    RawStr,
+    RawByteStr,
 }
 
 impl Mode {
     pub fn in_single_quotes(self) -> bool {
         match self {
             Mode::Char | Mode::Byte => true,
-            Mode::Str | Mode::ByteStr => false,
+            Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => false,
         }
     }
 
@@ -146,8 +136,8 @@ impl Mode {
 
     pub fn is_bytes(self) -> bool {
         match self {
-            Mode::Byte | Mode::ByteStr => true,
-            Mode::Char | Mode::Str => false,
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
+            Mode::Char | Mode::Str | Mode::RawStr => false,
         }
     }
 }
@@ -345,7 +335,7 @@ where
 
 fn byte_from_char(c: char) -> u8 {
     let res = c as u32;
-    assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::Byte(Str)");
+    assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::ByteStr");
     res as u8
 }
 
diff --git a/src/librustc_lexer/src/unescape/tests.rs b/src/librustc_lexer/src/unescape/tests.rs
index e7b1ff6479d..f2b751a78f2 100644
--- a/src/librustc_lexer/src/unescape/tests.rs
+++ b/src/librustc_lexer/src/unescape/tests.rs
@@ -102,7 +102,7 @@ fn test_unescape_char_good() {
 fn test_unescape_str_good() {
     fn check(literal_text: &str, expected: &str) {
         let mut buf = Ok(String::with_capacity(literal_text.len()));
-        unescape_str(literal_text, &mut |range, c| {
+        unescape_literal(literal_text, Mode::Str, &mut |range, c| {
             if let Ok(b) = &mut buf {
                 match c {
                     Ok(c) => b.push(c),
@@ -222,7 +222,7 @@ fn test_unescape_byte_good() {
 fn test_unescape_byte_str_good() {
     fn check(literal_text: &str, expected: &[u8]) {
         let mut buf = Ok(Vec::with_capacity(literal_text.len()));
-        unescape_byte_str(literal_text, &mut |range, c| {
+        unescape_byte_literal(literal_text, Mode::ByteStr, &mut |range, c| {
             if let Ok(b) = &mut buf {
                 match c {
                     Ok(c) => b.push(c),
@@ -246,7 +246,7 @@ fn test_unescape_byte_str_good() {
 fn test_unescape_raw_str() {
     fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
         let mut unescaped = Vec::with_capacity(literal.len());
-        unescape_raw_str(literal, &mut |range, res| unescaped.push((range, res)));
+        unescape_literal(literal, Mode::RawStr, &mut |range, res| unescaped.push((range, res)));
         assert_eq!(unescaped, expected);
     }
 
@@ -258,7 +258,9 @@ fn test_unescape_raw_str() {
 fn test_unescape_raw_byte_str() {
     fn check(literal: &str, expected: &[(Range<usize>, Result<u8, EscapeError>)]) {
         let mut unescaped = Vec::with_capacity(literal.len());
-        unescape_raw_byte_str(literal, &mut |range, res| unescaped.push((range, res)));
+        unescape_byte_literal(literal, Mode::RawByteStr, &mut |range, res| {
+            unescaped.push((range, res))
+        });
         assert_eq!(unescaped, expected);
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 7d5289cd46f..327dbecba26 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -28,8 +28,8 @@ use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
-use rustc_feature::Stability;
 use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
+use rustc_feature::{GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -1817,13 +1817,21 @@ impl EarlyLintPass for IncompleteFeatures {
             .map(|(name, span, _)| (name, span))
             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
             .filter(|(name, _)| rustc_feature::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
-            .for_each(|(name, &span)| {
+            .for_each(|(&name, &span)| {
                 cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
-                    lint.build(&format!(
-                        "the feature `{}` is incomplete and may cause the compiler to crash",
+                    let mut builder = lint.build(&format!(
+                        "the feature `{}` is incomplete and may not be safe to use \
+                         and/or cause compiler crashes",
                         name,
-                    ))
-                    .emit()
+                    ));
+                    if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
+                        builder.note(&format!(
+                            "see issue #{} <https://github.com/rust-lang/rust/issues/{}> \
+                             for more information",
+                            n, n,
+                        ));
+                    }
+                    builder.emit();
                 })
             });
     }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 1d97b286024..703c2a7a443 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -888,7 +888,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
             | ty::Placeholder(..)
-            | ty::UnnormalizedProjection(..)
             | ty::Projection(..)
             | ty::Opaque(..)
             | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index ddd252cb290..c24079a6e4b 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -380,11 +380,27 @@ trait UnusedDelimLint {
     );
 
     fn is_expr_delims_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool {
-        followed_by_block
-            && match inner.kind {
-                ExprKind::Ret(_) | ExprKind::Break(..) => true,
-                _ => parser::contains_exterior_struct_lit(&inner),
+        // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
+        let lhs_needs_parens = {
+            let mut innermost = inner;
+            loop {
+                if let ExprKind::Binary(_, lhs, _rhs) = &innermost.kind {
+                    innermost = lhs;
+                    if !rustc_ast::util::classify::expr_requires_semi_to_be_stmt(innermost) {
+                        break true;
+                    }
+                } else {
+                    break false;
+                }
             }
+        };
+
+        lhs_needs_parens
+            || (followed_by_block
+                && match inner.kind {
+                    ExprKind::Ret(_) | ExprKind::Break(..) => true,
+                    _ => parser::contains_exterior_struct_lit(&inner),
+                })
     }
 
     fn emit_unused_delims_expr(
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 8db107ed68a..2a2169880a5 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -7,7 +7,7 @@
 #![feature(nll)]
 #![feature(or_patterns)]
 #![feature(proc_macro_internals)]
-#![feature(specialization)]
+#![feature(specialization)] // FIXME: min_specialization ICEs
 #![feature(stmt_expr_attributes)]
 #![recursion_limit = "256"]
 
diff --git a/src/librustc_middle/dep_graph/mod.rs b/src/librustc_middle/dep_graph/mod.rs
index f997df25e99..682b335c5d0 100644
--- a/src/librustc_middle/dep_graph/mod.rs
+++ b/src/librustc_middle/dep_graph/mod.rs
@@ -72,9 +72,9 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
         })
     }
 
-    fn read_deps<OP>(op: OP) -> ()
+    fn read_deps<OP>(op: OP)
     where
-        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>) -> (),
+        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>),
     {
         ty::tls::with_context_opt(|icx| {
             let icx = if let Some(icx) = icx { icx } else { return };
diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs
index de0373c1384..b823516d64f 100644
--- a/src/librustc_middle/hir/map/mod.rs
+++ b/src/librustc_middle/hir/map/mod.rs
@@ -390,11 +390,7 @@ impl<'hir> Map<'hir> {
     /// Given a `HirId`, returns the `BodyId` associated with it,
     /// if the node is a body owner, otherwise returns `None`.
     pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option<BodyId> {
-        if let Some(node) = self.find(hir_id) {
-            associated_body(node)
-        } else {
-            bug!("no entry for id `{}`", hir_id)
-        }
+        self.find(hir_id).map(associated_body).flatten()
     }
 
     /// Given a body owner's id, returns the `BodyId` associated with it.
diff --git a/src/librustc_middle/hir/mod.rs b/src/librustc_middle/hir/mod.rs
index 7ab66411b21..1e3676496ce 100644
--- a/src/librustc_middle/hir/mod.rs
+++ b/src/librustc_middle/hir/mod.rs
@@ -78,7 +78,6 @@ pub fn provide(providers: &mut Providers<'_>) {
         &tcx.untracked_crate.modules[&module]
     };
     providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
-    providers.hir_owner_nodes =
-        |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_ref().map(|nodes| &**nodes);
+    providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
     map::provide(providers);
 }
diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs
index b17a77e0f6f..d0f627d8bc5 100644
--- a/src/librustc_middle/lib.rs
+++ b/src/librustc_middle/lib.rs
@@ -41,7 +41,7 @@
 #![feature(option_expect_none)]
 #![feature(or_patterns)]
 #![feature(range_is_empty)]
-#![feature(specialization)]
+#![feature(specialization)] // FIXME: min_specialization does not work
 #![feature(track_caller)]
 #![feature(trusted_len)]
 #![feature(vec_remove_item)]
diff --git a/src/librustc_middle/middle/region.rs b/src/librustc_middle/middle/region.rs
index c3eeea7662b..f02d8fe8ad6 100644
--- a/src/librustc_middle/middle/region.rs
+++ b/src/librustc_middle/middle/region.rs
@@ -4,7 +4,7 @@
 //! For more information about how MIR-based region-checking works,
 //! see the [rustc dev guide].
 //!
-//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/borrowck.html
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::ty::{self, DefIdTree, TyCtxt};
@@ -181,7 +181,7 @@ impl Scope {
                 // `blk`; reuse span of `blk` and shift `lo`
                 // forward to end of indexed statement.
                 //
-                // (This is the special case aluded to in the
+                // (This is the special case alluded to in the
                 // doc-comment for this method)
 
                 let stmt_span = blk.stmts[first_statement_index.index()].span;
diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/src/librustc_middle/mir/interpret/pointer.rs
index 0b060056499..70cc546199b 100644
--- a/src/librustc_middle/mir/interpret/pointer.rs
+++ b/src/librustc_middle/mir/interpret/pointer.rs
@@ -89,27 +89,35 @@ pub struct Pointer<Tag = ()> {
 
 static_assert_size!(Pointer, 16);
 
+/// Print the address of a pointer (without the tag)
+fn print_ptr_addr<Tag>(ptr: &Pointer<Tag>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    // Forward `alternate` flag to `alloc_id` printing.
+    if f.alternate() {
+        write!(f, "{:#?}", ptr.alloc_id)?;
+    } else {
+        write!(f, "{:?}", ptr.alloc_id)?;
+    }
+    // Print offset only if it is non-zero.
+    if ptr.offset.bytes() > 0 {
+        write!(f, "+0x{:x}", ptr.offset.bytes())?;
+    }
+    Ok(())
+}
+
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
 // We have to use `Debug` output for the tag, because `()` does not implement
 // `Display` so we cannot specialize that.
 impl<Tag: fmt::Debug> fmt::Debug for Pointer<Tag> {
     default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if f.alternate() {
-            write!(f, "{:#?}+0x{:x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag)
-        } else {
-            write!(f, "{:?}+0x{:x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag)
-        }
+        print_ptr_addr(self, f)?;
+        write!(f, "[{:?}]", self.tag)
     }
 }
 // Specialization for no tag
 impl fmt::Debug for Pointer<()> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if f.alternate() {
-            write!(f, "{:#?}+0x{:x}", self.alloc_id, self.offset.bytes())
-        } else {
-            write!(f, "{:?}+0x{:x}", self.alloc_id, self.offset.bytes())
-        }
+        print_ptr_addr(self, f)
     }
 }
 
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index 632607e3356..c889dbc0a44 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -239,6 +239,9 @@ pub struct CodegenUnit<'tcx> {
     size_estimate: Option<usize>,
 }
 
+/// 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)]
 pub enum Linkage {
     External,
diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs
index 2f3d89dc029..1f097f24942 100644
--- a/src/librustc_middle/mir/visit.rs
+++ b/src/librustc_middle/mir/visit.rs
@@ -427,13 +427,29 @@ macro_rules! make_mir_visitor {
                     TerminatorKind::Goto { .. } |
                     TerminatorKind::Resume |
                     TerminatorKind::Abort |
-                    TerminatorKind::Return |
                     TerminatorKind::GeneratorDrop |
                     TerminatorKind::Unreachable |
                     TerminatorKind::FalseEdges { .. } |
                     TerminatorKind::FalseUnwind { .. } => {
                     }
 
+                    TerminatorKind::Return => {
+                        // `return` logically moves from the return place `_0`. Note that the place
+                        // cannot be changed by any visitor, though.
+                        let $($mutability)? local = RETURN_PLACE;
+                        self.visit_local(
+                            & $($mutability)? local,
+                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
+                            source_location,
+                        );
+
+                        assert_eq!(
+                            local,
+                            RETURN_PLACE,
+                            "`MutVisitor` tried to mutate return place of `return` terminator"
+                        );
+                    }
+
                     TerminatorKind::SwitchInt {
                         discr,
                         switch_ty,
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index 2ceba519494..13cf9a934b7 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -1164,6 +1164,12 @@ rustc_queries! {
             desc { "evaluating trait selection obligation `{}`", goal.value }
         }
 
+        query type_implements_trait(
+            key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
+        ) -> bool {
+            desc { "evaluating `type_implements_trait` `{:?}`", key }
+        }
+
         /// Do not call this query directly: part of the `Eq` type-op
         query type_op_ascribe_user_type(
             goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>
diff --git a/src/librustc_middle/traits/query.rs b/src/librustc_middle/traits/query.rs
index 67f4b15f919..e030125b5b1 100644
--- a/src/librustc_middle/traits/query.rs
+++ b/src/librustc_middle/traits/query.rs
@@ -255,8 +255,6 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Infer(_)
         | ty::Bound(..)
         | ty::Generator(..) => false,
-
-        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
     }
 }
 
diff --git a/src/librustc_middle/ty/adjustment.rs b/src/librustc_middle/ty/adjustment.rs
index efd5adeba8c..52ebcd63e7c 100644
--- a/src/librustc_middle/ty/adjustment.rs
+++ b/src/librustc_middle/ty/adjustment.rs
@@ -2,6 +2,7 @@ use crate::ty::subst::SubstsRef;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 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)]
@@ -117,11 +118,11 @@ pub struct OverloadedDeref<'tcx> {
 impl<'tcx> OverloadedDeref<'tcx> {
     pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> (DefId, SubstsRef<'tcx>) {
         let trait_def_id = match self.mutbl {
-            hir::Mutability::Not => tcx.lang_items().deref_trait(),
-            hir::Mutability::Mut => tcx.lang_items().deref_mut_trait(),
+            hir::Mutability::Not => tcx.require_lang_item(DerefTraitLangItem, None),
+            hir::Mutability::Mut => tcx.require_lang_item(DerefMutTraitLangItem, None),
         };
         let method_def_id = tcx
-            .associated_items(trait_def_id.unwrap())
+            .associated_items(trait_def_id)
             .in_definition_order()
             .find(|m| m.kind == ty::AssocKind::Fn)
             .unwrap()
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index 86b740b8503..7feb080d4b8 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -1878,7 +1878,6 @@ impl<'tcx> TyCtxt<'tcx> {
             Bound,
             Param,
             Infer,
-            UnnormalizedProjection,
             Projection,
             Opaque,
             Foreign
diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs
index f3b6a53dfeb..cf63a659e6c 100644
--- a/src/librustc_middle/ty/error.rs
+++ b/src/librustc_middle/ty/error.rs
@@ -284,7 +284,6 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
             ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
             ty::Projection(_) => "associated type".into(),
-            ty::UnnormalizedProjection(_) => "non-normalized associated type".into(),
             ty::Param(p) => format!("type parameter `{}`", p).into(),
             ty::Opaque(..) => "opaque type".into(),
             ty::Error => "type error".into(),
@@ -323,7 +322,6 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::Placeholder(..) => "higher-ranked type".into(),
             ty::Bound(..) => "bound type variable".into(),
             ty::Projection(_) => "associated type".into(),
-            ty::UnnormalizedProjection(_) => "associated type".into(),
             ty::Param(_) => "type parameter".into(),
             ty::Opaque(..) => "opaque type".into(),
         }
diff --git a/src/librustc_middle/ty/fast_reject.rs b/src/librustc_middle/ty/fast_reject.rs
index 2a937d6581d..16d8e379407 100644
--- a/src/librustc_middle/ty/fast_reject.rs
+++ b/src/librustc_middle/ty/fast_reject.rs
@@ -90,7 +90,6 @@ pub fn simplify_type(
         ty::Never => Some(NeverSimplifiedType),
         ty::Tuple(ref tys) => Some(TupleSimplifiedType(tys.len())),
         ty::FnPtr(ref f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
-        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
         ty::Projection(_) | ty::Param(_) => {
             if can_simplify_params {
                 // In normalized types, projections don't unify with
diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs
index a88f3628109..042ffc4d1e5 100644
--- a/src/librustc_middle/ty/flags.rs
+++ b/src/librustc_middle/ty/flags.rs
@@ -121,11 +121,6 @@ impl FlagComputation {
                 self.add_projection_ty(data);
             }
 
-            &ty::UnnormalizedProjection(ref data) => {
-                self.add_flags(TypeFlags::HAS_TY_PROJECTION);
-                self.add_projection_ty(data);
-            }
-
             &ty::Opaque(_, substs) => {
                 self.add_flags(TypeFlags::HAS_TY_OPAQUE);
                 self.add_substs(substs);
diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs
index 88cc63a7285..1ce079821a2 100644
--- a/src/librustc_middle/ty/instance.rs
+++ b/src/librustc_middle/ty/instance.rs
@@ -4,7 +4,7 @@ use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
 use rustc_errors::ErrorReported;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_hir::lang_items::DropInPlaceFnLangItem;
+use rustc_hir::lang_items::{DropInPlaceFnLangItem, FnOnceTraitLangItem};
 use rustc_macros::HashStable;
 
 use std::fmt;
@@ -375,7 +375,7 @@ impl<'tcx> Instance<'tcx> {
         substs: ty::SubstsRef<'tcx>,
     ) -> Instance<'tcx> {
         debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs);
-        let fn_once = tcx.lang_items().fn_once_trait().unwrap();
+        let fn_once = tcx.require_lang_item(FnOnceTraitLangItem, None);
         let call_once = tcx
             .associated_items(fn_once)
             .in_definition_order()
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 7c4e4d095bc..2d49d85c4df 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -8,6 +8,7 @@ use rustc_ast::ast::{self, IntTy, UintTy};
 use rustc_attr as attr;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
+use rustc_hir::lang_items::{GeneratorStateLangItem, PinTypeLangItem};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
@@ -1241,11 +1242,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 tcx.layout_raw(param_env.and(normalized))?
             }
 
-            ty::Bound(..)
-            | ty::Placeholder(..)
-            | ty::UnnormalizedProjection(..)
-            | ty::GeneratorWitness(..)
-            | ty::Infer(_) => bug!("Layout::compute: unexpected type `{}`", ty),
+            ty::Bound(..) | ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
+                bug!("Layout::compute: unexpected type `{}`", ty)
+            }
 
             ty::Param(_) | ty::Error => {
                 return Err(LayoutError::Unknown(ty));
@@ -2138,7 +2137,6 @@ where
             }
 
             ty::Projection(_)
-            | ty::UnnormalizedProjection(..)
             | ty::Bound(..)
             | ty::Placeholder(..)
             | ty::Opaque(..)
@@ -2317,13 +2315,13 @@ impl<'tcx> ty::Instance<'tcx> {
                 let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
                 let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
 
-                let pin_did = tcx.lang_items().pin_type().unwrap();
+                let pin_did = tcx.require_lang_item(PinTypeLangItem, None);
                 let pin_adt_ref = tcx.adt_def(pin_did);
                 let pin_substs = tcx.intern_substs(&[env_ty.into()]);
                 let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
 
                 sig.map_bound(|sig| {
-                    let state_did = tcx.lang_items().gen_state().unwrap();
+                    let state_did = tcx.require_lang_item(GeneratorStateLangItem, None);
                     let state_adt_ref = tcx.adt_def(state_did);
                     let state_substs = tcx.intern_substs(&[
                         sig.yield_ty.into(),
diff --git a/src/librustc_middle/ty/list.rs b/src/librustc_middle/ty/list.rs
new file mode 100644
index 00000000000..6427c547a8f
--- /dev/null
+++ b/src/librustc_middle/ty/list.rs
@@ -0,0 +1,149 @@
+use crate::arena::Arena;
+
+use rustc_serialize::{Encodable, Encoder};
+
+use std::cmp::{self, Ordering};
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::mem;
+use std::ops::Deref;
+use std::ptr;
+use std::slice;
+
+extern "C" {
+    /// A dummy type used to force `List` to be unsized while not requiring references to it be wide
+    /// pointers.
+    type OpaqueListContents;
+}
+
+/// A wrapper for slices with the additional invariant
+/// that the slice is interned and no other slice with
+/// the same contents can exist in the same context.
+/// This means we can use pointer for both
+/// equality comparisons and hashing.
+/// Note: `Slice` was already taken by the `Ty`.
+#[repr(C)]
+pub struct List<T> {
+    len: usize,
+    data: [T; 0],
+    opaque: OpaqueListContents,
+}
+
+unsafe impl<T: Sync> Sync for List<T> {}
+
+impl<T: Copy> List<T> {
+    #[inline]
+    pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> {
+        assert!(!mem::needs_drop::<T>());
+        assert!(mem::size_of::<T>() != 0);
+        assert!(!slice.is_empty());
+
+        // Align up the size of the len (usize) field
+        let align = mem::align_of::<T>();
+        let align_mask = align - 1;
+        let offset = mem::size_of::<usize>();
+        let offset = (offset + align_mask) & !align_mask;
+
+        let size = offset + slice.len() * mem::size_of::<T>();
+
+        let mem = arena
+            .dropless
+            .alloc_raw(size, cmp::max(mem::align_of::<T>(), mem::align_of::<usize>()));
+        unsafe {
+            let result = &mut *(mem.as_mut_ptr() as *mut List<T>);
+            // Write the length
+            result.len = slice.len();
+
+            // Write the elements
+            let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len);
+            arena_slice.copy_from_slice(slice);
+
+            result
+        }
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for List<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+impl<T: Encodable> Encodable for List<T> {
+    #[inline]
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        (**self).encode(s)
+    }
+}
+
+impl<T> Ord for List<T>
+where
+    T: Ord,
+{
+    fn cmp(&self, other: &List<T>) -> Ordering {
+        if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
+    }
+}
+
+impl<T> PartialOrd for List<T>
+where
+    T: PartialOrd,
+{
+    fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> {
+        if self == other {
+            Some(Ordering::Equal)
+        } else {
+            <[T] as PartialOrd>::partial_cmp(&**self, &**other)
+        }
+    }
+}
+
+impl<T: PartialEq> PartialEq for List<T> {
+    #[inline]
+    fn eq(&self, other: &List<T>) -> bool {
+        ptr::eq(self, other)
+    }
+}
+impl<T: Eq> Eq for List<T> {}
+
+impl<T> Hash for List<T> {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        (self as *const List<T>).hash(s)
+    }
+}
+
+impl<T> Deref for List<T> {
+    type Target = [T];
+    #[inline(always)]
+    fn deref(&self) -> &[T] {
+        self.as_ref()
+    }
+}
+
+impl<T> AsRef<[T]> for List<T> {
+    #[inline(always)]
+    fn as_ref(&self) -> &[T] {
+        unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
+    }
+}
+
+impl<'a, T> IntoIterator for &'a List<T> {
+    type Item = &'a T;
+    type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
+    #[inline(always)]
+    fn into_iter(self) -> Self::IntoIter {
+        self[..].iter()
+    }
+}
+
+impl<T> List<T> {
+    #[inline(always)]
+    pub fn empty<'a>() -> &'a List<T> {
+        #[repr(align(64), C)]
+        struct EmptySlice([u8; 64]);
+        static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]);
+        assert!(mem::align_of::<T>() <= 64);
+        unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
+    }
+}
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 02fe7adcd07..6d6e1699feb 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -4,7 +4,6 @@ pub use self::BorrowKind::*;
 pub use self::IntVarValue::*;
 pub use self::Variance::*;
 
-use crate::arena::Arena;
 use crate::hir::exports::ExportMap;
 use crate::ich::StableHashingContext;
 use crate::infer::canonical::Canonical;
@@ -43,13 +42,11 @@ use rustc_span::Span;
 use rustc_target::abi::{Align, VariantIdx};
 
 use std::cell::RefCell;
-use std::cmp::{self, Ordering};
+use std::cmp::Ordering;
 use std::fmt;
 use std::hash::{Hash, Hasher};
-use std::ops::Deref;
 use std::ops::Range;
-use std::slice;
-use std::{mem, ptr};
+use std::ptr;
 
 pub use self::sty::BoundRegion::*;
 pub use self::sty::InferTy::*;
@@ -81,6 +78,8 @@ pub use self::context::{
 
 pub use self::instance::{Instance, InstanceDef};
 
+pub use self::list::List;
+
 pub use self::trait_def::TraitDef;
 
 pub use self::query::queries;
@@ -112,6 +111,7 @@ pub mod walk;
 mod context;
 mod diagnostics;
 mod instance;
+mod list;
 mod structural_impls;
 mod sty;
 
@@ -280,7 +280,7 @@ impl<'tcx> AssociatedItems<'tcx> {
         &self,
         name: Symbol,
     ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
-        self.items.get_by_key(&name).map(|v| *v)
+        self.items.get_by_key(&name).copied()
     }
 
     /// Returns an iterator over all associated items with the given name.
@@ -555,7 +555,7 @@ bitflags! {
                                           | TypeFlags::HAS_CT_PLACEHOLDER.bits
                                           | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
 
-        /// Does this have [Projection] or [UnnormalizedProjection]?
+        /// Does this have [Projection]?
         const HAS_TY_PROJECTION           = 1 << 10;
         /// Does this have [Opaque]?
         const HAS_TY_OPAQUE               = 1 << 11;
@@ -663,148 +663,9 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
 impl<'tcx> rustc_serialize::UseSpecializedEncodable for Ty<'tcx> {}
 impl<'tcx> rustc_serialize::UseSpecializedDecodable for Ty<'tcx> {}
-
-pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>;
-
-extern "C" {
-    /// A dummy type used to force `List` to be unsized while not requiring references to it be wide
-    /// pointers.
-    type OpaqueListContents;
-}
-
-/// A wrapper for slices with the additional invariant
-/// that the slice is interned and no other slice with
-/// the same contents can exist in the same context.
-/// This means we can use pointer for both
-/// equality comparisons and hashing.
-/// Note: `Slice` was already taken by the `Ty`.
-#[repr(C)]
-pub struct List<T> {
-    len: usize,
-    data: [T; 0],
-    opaque: OpaqueListContents,
-}
-
-unsafe impl<T: Sync> Sync for List<T> {}
-
-impl<T: Copy> List<T> {
-    #[inline]
-    fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> {
-        assert!(!mem::needs_drop::<T>());
-        assert!(mem::size_of::<T>() != 0);
-        assert!(!slice.is_empty());
-
-        // Align up the size of the len (usize) field
-        let align = mem::align_of::<T>();
-        let align_mask = align - 1;
-        let offset = mem::size_of::<usize>();
-        let offset = (offset + align_mask) & !align_mask;
-
-        let size = offset + slice.len() * mem::size_of::<T>();
-
-        let mem = arena
-            .dropless
-            .alloc_raw(size, cmp::max(mem::align_of::<T>(), mem::align_of::<usize>()));
-        unsafe {
-            let result = &mut *(mem.as_mut_ptr() as *mut List<T>);
-            // Write the length
-            result.len = slice.len();
-
-            // Write the elements
-            let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len);
-            arena_slice.copy_from_slice(slice);
-
-            result
-        }
-    }
-}
-
-impl<T: fmt::Debug> fmt::Debug for List<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        (**self).fmt(f)
-    }
-}
-
-impl<T: Encodable> Encodable for List<T> {
-    #[inline]
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
-    }
-}
-
-impl<T> Ord for List<T>
-where
-    T: Ord,
-{
-    fn cmp(&self, other: &List<T>) -> Ordering {
-        if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
-    }
-}
-
-impl<T> PartialOrd for List<T>
-where
-    T: PartialOrd,
-{
-    fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> {
-        if self == other {
-            Some(Ordering::Equal)
-        } else {
-            <[T] as PartialOrd>::partial_cmp(&**self, &**other)
-        }
-    }
-}
-
-impl<T: PartialEq> PartialEq for List<T> {
-    #[inline]
-    fn eq(&self, other: &List<T>) -> bool {
-        ptr::eq(self, other)
-    }
-}
-impl<T: Eq> Eq for List<T> {}
-
-impl<T> Hash for List<T> {
-    #[inline]
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        (self as *const List<T>).hash(s)
-    }
-}
-
-impl<T> Deref for List<T> {
-    type Target = [T];
-    #[inline(always)]
-    fn deref(&self) -> &[T] {
-        self.as_ref()
-    }
-}
-
-impl<T> AsRef<[T]> for List<T> {
-    #[inline(always)]
-    fn as_ref(&self) -> &[T] {
-        unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
-    }
-}
-
-impl<'a, T> IntoIterator for &'a List<T> {
-    type Item = &'a T;
-    type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
-    #[inline(always)]
-    fn into_iter(self) -> Self::IntoIter {
-        self[..].iter()
-    }
-}
-
 impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx List<Ty<'tcx>> {}
 
-impl<T> List<T> {
-    #[inline(always)]
-    pub fn empty<'a>() -> &'a List<T> {
-        #[repr(align(64), C)]
-        struct EmptySlice([u8; 64]);
-        static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]);
-        assert!(mem::align_of::<T>() <= 64);
-        unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
-    }
-}
+pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>;
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UpvarPath {
diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs
index 4fd4d0d1f06..afd670b8577 100644
--- a/src/librustc_middle/ty/outlives.rs
+++ b/src/librustc_middle/ty/outlives.rs
@@ -135,8 +135,6 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
                 }
             }
 
-            ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
             // We assume that inference variables are fully resolved.
             // So, if we encounter an inference variable, just record
             // the unresolved variable as a component.
diff --git a/src/librustc_middle/ty/print/mod.rs b/src/librustc_middle/ty/print/mod.rs
index 6bdc65eb056..69b36980bd7 100644
--- a/src/librustc_middle/ty/print/mod.rs
+++ b/src/librustc_middle/ty/print/mod.rs
@@ -294,7 +294,6 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
         | ty::FnPtr(_)
         | ty::Projection(_)
         | ty::Placeholder(..)
-        | ty::UnnormalizedProjection(..)
         | ty::Param(_)
         | ty::Opaque(..)
         | ty::Infer(_)
diff --git a/src/librustc_middle/ty/print/obsolete.rs b/src/librustc_middle/ty/print/obsolete.rs
index 757a8bd23f6..41a6cd5466f 100644
--- a/src/librustc_middle/ty/print/obsolete.rs
+++ b/src/librustc_middle/ty/print/obsolete.rs
@@ -148,7 +148,6 @@ impl DefPathBasedNames<'tcx> {
             | ty::Bound(..)
             | ty::Infer(_)
             | ty::Placeholder(..)
-            | ty::UnnormalizedProjection(..)
             | ty::Projection(..)
             | ty::Param(_)
             | ty::GeneratorWitness(_)
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 2684492a406..64909cd0c46 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -540,9 +540,6 @@ pub trait PrettyPrinter<'tcx>:
                 p!(print_def_path(def_id, &[]));
             }
             ty::Projection(ref data) => p!(print(data)),
-            ty::UnnormalizedProjection(ref data) => {
-                p!(write("Unnormalized("), print(data), write(")"))
-            }
             ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
             ty::Opaque(def_id, substs) => {
                 // FIXME(eddyb) print this with `print_def_path`.
@@ -701,12 +698,14 @@ pub trait PrettyPrinter<'tcx>:
                 if self.tcx().sess.verbose() {
                     p!(write("{:?}", sz));
                 } else if let ty::ConstKind::Unevaluated(..) = sz.val {
-                    // do not try to evaluate unevaluated constants. If we are const evaluating an
+                    // Do not try to evaluate unevaluated constants. If we are const evaluating an
                     // array length anon const, rustc will (with debug assertions) print the
                     // constant's path. Which will end up here again.
                     p!(write("_"));
                 } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) {
                     p!(write("{}", n));
+                } else if let ty::ConstKind::Param(param) = sz.val {
+                    p!(write("{}", param));
                 } else {
                     p!(write("_"));
                 }
diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs
index 239691dbd17..4acf766f033 100644
--- a/src/librustc_middle/ty/query/keys.rs
+++ b/src/librustc_middle/ty/query/keys.rs
@@ -295,3 +295,15 @@ impl Key for (Symbol, u32, u32) {
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs
index 9c198dd556a..d68bc7221f9 100644
--- a/src/librustc_middle/ty/relate.rs
+++ b/src/librustc_middle/ty/relate.rs
@@ -477,11 +477,6 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
             Ok(tcx.mk_fn_ptr(fty))
         }
 
-        (ty::UnnormalizedProjection(a_data), ty::UnnormalizedProjection(b_data)) => {
-            let projection_ty = relation.relate(a_data, b_data)?;
-            Ok(tcx.mk_ty(ty::UnnormalizedProjection(projection_ty)))
-        }
-
         // these two are already handled downstream in case of lazy normalization
         (ty::Projection(a_data), ty::Projection(b_data)) => {
             let projection_ty = relation.relate(a_data, b_data)?;
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index c8406a024ec..680b7187921 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -888,9 +888,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
             ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
             ty::Projection(ref data) => ty::Projection(data.fold_with(folder)),
-            ty::UnnormalizedProjection(ref data) => {
-                ty::UnnormalizedProjection(data.fold_with(folder))
-            }
             ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
 
             ty::Bool
@@ -931,9 +928,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::Generator(_did, ref substs, _) => substs.visit_with(visitor),
             ty::GeneratorWitness(ref types) => types.visit_with(visitor),
             ty::Closure(_did, ref substs) => substs.visit_with(visitor),
-            ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => {
-                data.visit_with(visitor)
-            }
+            ty::Projection(ref data) => data.visit_with(visitor),
             ty::Opaque(_, ref substs) => substs.visit_with(visitor),
 
             ty::Bool
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index a6cf3b7e2ee..2ad673b2c19 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -181,11 +181,6 @@ pub enum TyKind<'tcx> {
     /// `<T as Trait<..>>::N`.
     Projection(ProjectionTy<'tcx>),
 
-    /// A placeholder type used when we do not have enough information
-    /// to normalize the projection of an associated type to an
-    /// existing concrete type. Currently only used with chalk-engine.
-    UnnormalizedProjection(ProjectionTy<'tcx>),
-
     /// Opaque (`impl Trait`) type found in a return type.
     /// The `DefId` comes either from
     /// * the `impl Trait` ast::Ty node,
@@ -2186,8 +2181,6 @@ impl<'tcx> TyS<'tcx> {
 
             ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false,
 
-            ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
             ty::Infer(ty::TyVar(_)) => false,
 
             ty::Bound(..)
diff --git a/src/librustc_middle/ty/trait_def.rs b/src/librustc_middle/ty/trait_def.rs
index 89bcb240d90..8f125098ee6 100644
--- a/src/librustc_middle/ty/trait_def.rs
+++ b/src/librustc_middle/ty/trait_def.rs
@@ -171,10 +171,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
         let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id);
 
-        blanket_impls
-            .into_iter()
-            .chain(non_blanket_impls.into_iter().map(|(_, v)| v).flatten())
-            .cloned()
+        blanket_impls.iter().chain(non_blanket_impls.iter().map(|(_, v)| v).flatten()).cloned()
     }
 }
 
diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs
index a89927ecfb7..f9c10488ffb 100644
--- a/src/librustc_middle/ty/util.rs
+++ b/src/librustc_middle/ty/util.rs
@@ -745,8 +745,7 @@ impl<'tcx> ty::TyS<'tcx> {
             | ty::Opaque(..)
             | ty::Param(_)
             | ty::Placeholder(_)
-            | ty::Projection(_)
-            | ty::UnnormalizedProjection(_) => false,
+            | ty::Projection(_) => false,
         }
     }
 
@@ -1077,7 +1076,6 @@ pub fn needs_drop_components(
         // These require checking for `Copy` bounds or `Adt` destructors.
         ty::Adt(..)
         | ty::Projection(..)
-        | ty::UnnormalizedProjection(..)
         | ty::Param(_)
         | ty::Bound(..)
         | ty::Placeholder(..)
diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs
index b6cadd00996..0093c60d768 100644
--- a/src/librustc_middle/ty/walk.rs
+++ b/src/librustc_middle/ty/walk.rs
@@ -127,7 +127,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                 stack.push(ty.into());
                 stack.push(lt.into());
             }
-            ty::Projection(data) | ty::UnnormalizedProjection(data) => {
+            ty::Projection(data) => {
                 stack.extend(data.substs.iter().copied().rev());
             }
             ty::Dynamic(obj, lt) => {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index d3ab7df817b..a3ee49651ba 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -209,7 +209,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         nll_errors,
     } = nll::compute_regions(
         infcx,
-        def_id.to_def_id(),
+        def_id,
         free_regions,
         body,
         &promoted,
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index 29636a06709..b820b79c47f 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -2,7 +2,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Diagnostic;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::{
@@ -157,7 +157,7 @@ fn populate_polonius_move_facts(
 /// This may result in errors being reported.
 pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
     universal_regions: UniversalRegions<'tcx>,
     body: &Body<'tcx>,
     promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -272,7 +272,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     // Dump facts if requested.
     let polonius_output = all_facts.and_then(|all_facts| {
         if infcx.tcx.sess.opts.debugging_opts.nll_facts {
-            let def_path = infcx.tcx.def_path(def_id);
+            let def_path = infcx.tcx.def_path(def_id.to_def_id());
             let dir_path =
                 PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate());
             all_facts.write_to_dir(dir_path, location_table).unwrap();
@@ -292,7 +292,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
 
     // Solve the region constraints.
     let (closure_region_requirements, nll_errors) =
-        regioncx.solve(infcx, &body, def_id, polonius_output.clone());
+        regioncx.solve(infcx, &body, def_id.to_def_id(), polonius_output.clone());
 
     if !nll_errors.is_empty() {
         // Suppress unhelpful extra errors in `infer_opaque_types`.
diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs
index 894a997ea7a..edd2dc3c2de 100644
--- a/src/librustc_mir/borrow_check/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/type_check/input_output.rs
@@ -33,35 +33,37 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         //
         // e.g., `|x: FxHashMap<_, &'static u32>| ...`
         let user_provided_sig;
-        if !self.tcx().is_closure(self.mir_def_id) {
+        if !self.tcx().is_closure(self.mir_def_id.to_def_id()) {
             user_provided_sig = None;
         } else {
-            let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id.expect_local());
-            user_provided_sig = match typeck_tables.user_provided_sigs.get(&self.mir_def_id) {
-                None => None,
-                Some(user_provided_poly_sig) => {
-                    // Instantiate the canonicalized variables from
-                    // user-provided signature (e.g., the `_` in the code
-                    // above) with fresh variables.
-                    let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
-                        body.span,
-                        &user_provided_poly_sig,
-                    );
-
-                    // Replace the bound items in the fn sig with fresh
-                    // variables, so that they represent the view from
-                    // "inside" the closure.
-                    Some(
-                        self.infcx
-                            .replace_bound_vars_with_fresh_vars(
+            let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
+            user_provided_sig =
+                match typeck_tables.user_provided_sigs.get(&self.mir_def_id.to_def_id()) {
+                    None => None,
+                    Some(user_provided_poly_sig) => {
+                        // Instantiate the canonicalized variables from
+                        // user-provided signature (e.g., the `_` in the code
+                        // above) with fresh variables.
+                        let (poly_sig, _) =
+                            self.infcx.instantiate_canonical_with_fresh_inference_vars(
                                 body.span,
-                                LateBoundRegionConversionTime::FnCall,
-                                &poly_sig,
-                            )
-                            .0,
-                    )
+                                &user_provided_poly_sig,
+                            );
+
+                        // Replace the bound items in the fn sig with fresh
+                        // variables, so that they represent the view from
+                        // "inside" the closure.
+                        Some(
+                            self.infcx
+                                .replace_bound_vars_with_fresh_vars(
+                                    body.span,
+                                    LateBoundRegionConversionTime::FnCall,
+                                    &poly_sig,
+                                )
+                                .0,
+                        )
+                    }
                 }
-            }
         };
 
         debug!(
@@ -120,7 +122,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if let Err(terr) = self.eq_opaque_type_and_type(
             mir_output_ty,
             normalized_output_ty,
-            self.mir_def_id,
+            self.mir_def_id.to_def_id(),
             Locations::All(output_span),
             ConstraintCategory::BoringNoLocation,
         ) {
@@ -143,7 +145,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             if let Err(err) = self.eq_opaque_type_and_type(
                 mir_output_ty,
                 user_provided_output_ty,
-                self.mir_def_id,
+                self.mir_def_id.to_def_id(),
                 Locations::All(output_span),
                 ConstraintCategory::BoringNoLocation,
             ) {
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index ee8a4358147..bad176c603f 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::lang_items::{CoerceUnsizedTraitLangItem, CopyTraitLangItem, SizedTraitLangItem};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -108,26 +109,22 @@ mod relate_tys;
 ///
 /// - `infcx` -- inference context to use
 /// - `param_env` -- parameter environment to use for trait solving
-/// - `mir` -- MIR to type-check
-/// - `mir_def_id` -- DefId from which the MIR is derived (must be local)
-/// - `region_bound_pairs` -- the implied outlives obligations between type parameters
-///   and lifetimes (e.g., `&'a T` implies `T: 'a`)
-/// - `implicit_region_bound` -- a region which all generic parameters are assumed
-///   to outlive; should represent the fn body
-/// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
-///   the types of the input parameters found in the MIR itself will be equated with these
-/// - `output_ty` -- fully liberated, but **not** normalized, expected return type;
-///   the type for the RETURN_PLACE will be equated with this
-/// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
-///   constraints for the regions in the types of variables
+/// - `body` -- MIR body to type-check
+/// - `promoted` -- map of promoted constants within `body`
+/// - `mir_def_id` -- `LocalDefId` from which the MIR is derived
+/// - `universal_regions` -- the universal regions from `body`s function signature
+/// - `location_table` -- MIR location map of `body`
+/// - `borrow_set` -- information about borrows occurring in `body`
+/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts
 /// - `flow_inits` -- results of a maybe-init dataflow analysis
 /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
+/// - `elements` -- MIR region map
 pub(crate) fn type_check<'mir, 'tcx>(
     infcx: &InferCtxt<'_, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     promoted: &IndexVec<Promoted, Body<'tcx>>,
-    mir_def_id: DefId,
+    mir_def_id: LocalDefId,
     universal_regions: &Rc<UniversalRegions<'tcx>>,
     location_table: &LocationTable,
     borrow_set: &BorrowSet<'tcx>,
@@ -191,7 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
 
 fn type_check_internal<'a, 'tcx, R>(
     infcx: &'a InferCtxt<'a, 'tcx>,
-    mir_def_id: DefId,
+    mir_def_id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
     body: &'a Body<'tcx>,
     promoted: &'a IndexVec<Promoted, Body<'tcx>>,
@@ -271,7 +268,7 @@ struct TypeVerifier<'a, 'b, 'tcx> {
     body: &'b Body<'tcx>,
     promoted: &'b IndexVec<Promoted, Body<'tcx>>,
     last_span: Span,
-    mir_def_id: DefId,
+    mir_def_id: LocalDefId,
     errors_reported: bool,
 }
 
@@ -506,7 +503,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
             let tcx = self.tcx();
             let trait_ref = ty::TraitRef {
-                def_id: tcx.lang_items().copy_trait().unwrap(),
+                def_id: tcx.require_lang_item(CopyTraitLangItem, Some(self.last_span)),
                 substs: tcx.mk_substs_trait(place_ty.ty, &[]),
             };
 
@@ -815,7 +812,7 @@ struct TypeChecker<'a, 'tcx> {
     /// User type annotations are shared between the main MIR and the MIR of
     /// all of the promoted items.
     user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
-    mir_def_id: DefId,
+    mir_def_id: LocalDefId,
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
@@ -963,7 +960,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     fn new(
         infcx: &'a InferCtxt<'a, 'tcx>,
         body: &'a Body<'tcx>,
-        mir_def_id: DefId,
+        mir_def_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
         implicit_region_bound: ty::Region<'tcx>,
@@ -1142,7 +1139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // When you have `let x: impl Foo = ...` in a closure,
                 // the resulting inferend values are stored with the
                 // def-id of the base function.
-                let parent_def_id = self.tcx().closure_base_def_id(self.mir_def_id);
+                let parent_def_id = self.tcx().closure_base_def_id(self.mir_def_id.to_def_id());
                 return self.eq_opaque_type_and_type(sub, sup, parent_def_id, locations, category);
             } else {
                 return Err(terr);
@@ -1472,7 +1469,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.check_rvalue(body, rv, location);
                 if !self.tcx().features().unsized_locals {
                     let trait_ref = ty::TraitRef {
-                        def_id: tcx.lang_items().sized_trait().unwrap(),
+                        def_id: tcx.require_lang_item(SizedTraitLangItem, Some(self.last_span)),
                         substs: tcx.mk_substs_trait(place_ty, &[]),
                     };
                     self.prove_trait_ref(
@@ -1994,7 +1991,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
                             let ccx = ConstCx::new_with_param_env(
                                 tcx,
-                                self.mir_def_id.expect_local(),
+                                self.mir_def_id,
                                 body,
                                 self.param_env,
                             );
@@ -2010,16 +2007,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 &traits::Obligation::new(
                                     ObligationCause::new(
                                         span,
-                                        self.tcx()
-                                            .hir()
-                                            .local_def_id_to_hir_id(self.mir_def_id.expect_local()),
+                                        self.tcx().hir().local_def_id_to_hir_id(self.mir_def_id),
                                         traits::ObligationCauseCode::RepeatVec(should_suggest),
                                     ),
                                     self.param_env,
                                     ty::Predicate::Trait(
                                         ty::Binder::bind(ty::TraitPredicate {
                                             trait_ref: ty::TraitRef::new(
-                                                self.tcx().lang_items().copy_trait().unwrap(),
+                                                self.tcx().require_lang_item(
+                                                    CopyTraitLangItem,
+                                                    Some(self.last_span),
+                                                ),
                                                 tcx.mk_substs_trait(ty, &[]),
                                             ),
                                         }),
@@ -2043,7 +2041,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
 
                 let trait_ref = ty::TraitRef {
-                    def_id: tcx.lang_items().sized_trait().unwrap(),
+                    def_id: tcx.require_lang_item(SizedTraitLangItem, Some(self.last_span)),
                     substs: tcx.mk_substs_trait(ty, &[]),
                 };
 
@@ -2141,7 +2139,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     CastKind::Pointer(PointerCast::Unsize) => {
                         let &ty = ty;
                         let trait_ref = ty::TraitRef {
-                            def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
+                            def_id: tcx.require_lang_item(
+                                CoerceUnsizedTraitLangItem,
+                                Some(self.last_span),
+                            ),
                             substs: tcx.mk_substs_trait(op.ty(body, tcx), &[ty.into()]),
                         };
 
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index b6c635fb22a..0637ebf959e 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -66,7 +66,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         intern_kind,
         ret,
         body.ignore_interior_mut_in_const_validation,
-    )?;
+    );
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret)
diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs
index e1146ef30d1..7f557e340bb 100644
--- a/src/librustc_mir/const_eval/mod.rs
+++ b/src/librustc_mir/const_eval/mod.rs
@@ -53,7 +53,7 @@ pub(crate) fn const_caller_location(
     let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
 
     let loc_place = ecx.alloc_caller_location(file, line, col);
-    intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false).unwrap();
+    intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false);
     ConstValue::Scalar(loc_place.ptr)
 }
 
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 9bb7c879505..eba4dd336ad 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -871,6 +871,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Our result will later be validated anyway, and there seems no good reason
         // to have to fail early here.  This is also more consistent with
         // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
+        // FIXME: We can hit delay_span_bug if this is an invalid const, interning finds
+        // that problem, but we never run validation to show an error. Can we ensure
+        // this does not happen?
         let val = self.tcx.const_eval_raw(param_env.and(gid))?;
         self.raw_const_to_mplace(val)
     }
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index 1c44101595d..02a7f24a1e3 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -5,10 +5,9 @@
 
 use super::validity::RefTracking;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::ErrorReported;
 use rustc_hir as hir;
-use rustc_middle::mir::interpret::{ErrorHandled, InterpResult};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::mir::interpret::InterpResult;
+use rustc_middle::ty::{self, query::TyCtxtAt, Ty};
 
 use rustc_ast::ast::Mutability;
 
@@ -29,43 +28,45 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
     /// The ectx from which we intern.
     ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
     /// Previously encountered safe references.
-    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
+    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>,
     /// A list of all encountered allocations. After type-based interning, we traverse this list to
     /// also intern allocations that are only referenced by a raw pointer or inside a union.
     leftover_allocations: &'rt mut FxHashSet<AllocId>,
-    /// The root node of the value that we're looking at. This field is never mutated and only used
+    /// The root kind of the value that we're looking at. This field is never mutated and only used
     /// for sanity assertions that will ICE when `const_qualif` screws up.
     mode: InternMode,
-    /// This field stores the mutability of the value *currently* being checked.
-    /// When encountering a mutable reference, we determine the pointee mutability
-    /// taking into account the mutability of the context: `& &mut i32` is entirely immutable,
-    /// despite the nested mutable reference!
-    /// The field gets updated when an `UnsafeCell` is encountered.
-    mutability: Mutability,
+    /// This field stores whether we are *currently* inside an `UnsafeCell`. This can affect
+    /// the intern mode of references we encounter.
+    inside_unsafe_cell: bool,
 
     /// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants
     /// for promoteds.
     /// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field
-    ignore_interior_mut_in_const_validation: bool,
+    ignore_interior_mut_in_const: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
 enum InternMode {
-    /// Mutable references must in fact be immutable due to their surrounding immutability in a
-    /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mut`
-    /// that will actually be treated as mutable.
-    Static,
-    /// UnsafeCell is OK in the value of a constant: `const FOO = Cell::new(0)` creates
-    /// a new cell every time it is used.
+    /// A static and its current mutability.  Below shared references inside a `static mut`,
+    /// this is *immutable*, and below mutable references inside an `UnsafeCell`, this
+    /// is *mutable*.
+    Static(hir::Mutability),
+    /// The "base value" of a const, which can have `UnsafeCell` (as in `const FOO: Cell<i32>`),
+    /// but that interior mutability is simply ignored.
     ConstBase,
-    /// `UnsafeCell` ICEs.
-    Const,
+    /// The "inner values" of a const with references, where `UnsafeCell` is an error.
+    ConstInner,
 }
 
 /// Signalling data structure to ensure we don't recurse
 /// into the memory of other constants or statics
 struct IsStaticOrFn;
 
+fn mutable_memory_in_const(tcx: TyCtxtAt<'_>, kind: &str) {
+    // FIXME: show this in validation instead so we can point at where in the value the error is?
+    tcx.sess.span_err(tcx.span, &format!("mutable memory ({}) is not allowed in constant", kind));
+}
+
 /// Intern an allocation without looking at its children.
 /// `mode` is the mode of the environment where we found this pointer.
 /// `mutablity` is the mutability of the place to be interned; even if that says
@@ -75,12 +76,11 @@ struct IsStaticOrFn;
 fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
     ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
     leftover_allocations: &'rt mut FxHashSet<AllocId>,
-    mode: InternMode,
     alloc_id: AllocId,
-    mutability: Mutability,
+    mode: InternMode,
     ty: Option<Ty<'tcx>>,
-) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
-    trace!("InternVisitor::intern {:?} with {:?}", alloc_id, mutability,);
+) -> Option<IsStaticOrFn> {
+    trace!("intern_shallow {:?} with {:?}", alloc_id, mode);
     // remove allocation
     let tcx = ecx.tcx;
     let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) {
@@ -89,14 +89,15 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
             // Pointer not found in local memory map. It is either a pointer to the global
             // map, or dangling.
             // If the pointer is dangling (neither in local nor global memory), we leave it
-            // to validation to error. The `delay_span_bug` ensures that we don't forget such
-            // a check in validation.
+            // to validation to error -- it has the much better error messages, pointing out where
+            // in the value the dangling reference lies.
+            // The `delay_span_bug` ensures that we don't forget such a check in validation.
             if tcx.get_global_alloc(alloc_id).is_none() {
                 tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
             }
             // treat dangling pointers like other statics
             // just to stop trying to recurse into them
-            return Ok(Some(IsStaticOrFn));
+            return Some(IsStaticOrFn);
         }
     };
     // This match is just a canary for future changes to `MemoryKind`, which most likely need
@@ -107,45 +108,45 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
     // Set allocation mutability as appropriate. This is used by LLVM to put things into
     // read-only memory, and also by Miri when evaluating other globals that
     // access this one.
-    if mode == InternMode::Static {
-        // When `ty` is `None`, we assume no interior mutability.
+    if let InternMode::Static(mutability) = mode {
+        // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
+        // no interior mutability.
         let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx.tcx, ecx.param_env, ecx.tcx.span));
         // For statics, allocation mutability is the combination of the place mutability and
         // the type mutability.
         // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
-        if mutability == Mutability::Not && frozen {
+        let immutable = mutability == Mutability::Not && frozen;
+        if immutable {
             alloc.mutability = Mutability::Not;
         } else {
             // Just making sure we are not "upgrading" an immutable allocation to mutable.
             assert_eq!(alloc.mutability, Mutability::Mut);
         }
     } else {
-        // We *could* be non-frozen at `ConstBase`, for constants like `Cell::new(0)`.
-        // But we still intern that as immutable as the memory cannot be changed once the
-        // initial value was computed.
-        // Constants are never mutable.
-        assert_eq!(
-            mutability,
-            Mutability::Not,
-            "Something went very wrong: mutability requested for a constant"
-        );
+        // No matter what, *constants are never mutable*. Mutating them is UB.
+        // See const_eval::machine::MemoryExtra::can_access_statics for why
+        // immutability is so important.
+
+        // There are no sensible checks we can do here; grep for `mutable_memory_in_const` to
+        // find the checks we are doing elsewhere to avoid even getting here for memory
+        // that "wants" to be mutable.
         alloc.mutability = Mutability::Not;
     };
     // link the alloc id to the actual allocation
     let alloc = tcx.intern_const_alloc(alloc);
     leftover_allocations.extend(alloc.relocations().iter().map(|&(_, ((), reloc))| reloc));
     tcx.set_alloc_id_memory(alloc_id, alloc);
-    Ok(None)
+    None
 }
 
 impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> {
     fn intern_shallow(
         &mut self,
         alloc_id: AllocId,
-        mutability: Mutability,
+        mode: InternMode,
         ty: Option<Ty<'tcx>>,
-    ) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
-        intern_shallow(self.ecx, self.leftover_allocations, self.mode, alloc_id, mutability, ty)
+    ) -> Option<IsStaticOrFn> {
+        intern_shallow(self.ecx, self.leftover_allocations, alloc_id, mode, ty)
     }
 }
 
@@ -166,22 +167,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
     ) -> InterpResult<'tcx> {
         if let Some(def) = mplace.layout.ty.ty_adt_def() {
             if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
+                if self.mode == InternMode::ConstInner && !self.ignore_interior_mut_in_const {
+                    // We do not actually make this memory mutable.  But in case the user
+                    // *expected* it to be mutable, make sure we error.  This is just a
+                    // sanity check to prevent users from accidentally exploiting the UB
+                    // they caused.  It also helps us to find cases where const-checking
+                    // failed to prevent an `UnsafeCell` (but as `ignore_interior_mut_in_const`
+                    // shows that part is not airtight).
+                    mutable_memory_in_const(self.ecx.tcx, "`UnsafeCell`");
+                }
                 // We are crossing over an `UnsafeCell`, we can mutate again. This means that
                 // References we encounter inside here are interned as pointing to mutable
                 // allocations.
-                let old = std::mem::replace(&mut self.mutability, Mutability::Mut);
-                if !self.ignore_interior_mut_in_const_validation {
-                    assert_ne!(
-                        self.mode,
-                        InternMode::Const,
-                        "UnsafeCells are not allowed behind references in constants. This should \
-                        have been prevented statically by const qualification. If this were \
-                        allowed one would be able to change a constant at one use site and other \
-                        use sites could observe that mutation.",
-                    );
-                }
+                // Remember the `old` value to handle nested `UnsafeCell`.
+                let old = std::mem::replace(&mut self.inside_unsafe_cell, true);
                 let walked = self.walk_aggregate(mplace, fields);
-                self.mutability = old;
+                self.inside_unsafe_cell = old;
                 return walked;
             }
         }
@@ -191,78 +192,92 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
     fn visit_value(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
         // Handle Reference types, as these are the only relocations supported by const eval.
         // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
+        let tcx = self.ecx.tcx;
         let ty = mplace.layout.ty;
-        if let ty::Ref(_, referenced_ty, mutability) = ty.kind {
+        if let ty::Ref(_, referenced_ty, ref_mutability) = ty.kind {
             let value = self.ecx.read_immediate(mplace.into())?;
             let mplace = self.ecx.ref_to_mplace(value)?;
+            assert_eq!(mplace.layout.ty, referenced_ty);
             // Handle trait object vtables.
             if let ty::Dynamic(..) =
-                self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind
+                tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind
             {
-                // Validation has already errored on an invalid vtable pointer so we can safely not
-                // do anything if this is not a real pointer.
+                // Validation will error (with a better message) on an invalid vtable pointer
+                // so we can safely not do anything if this is not a real pointer.
                 if let Scalar::Ptr(vtable) = mplace.meta.unwrap_meta() {
-                    // Explicitly choose `Immutable` here, since vtables are immutable, even
+                    // Explicitly choose const mode here, since vtables are immutable, even
                     // if the reference of the fat pointer is mutable.
-                    self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?;
+                    self.intern_shallow(vtable.alloc_id, InternMode::ConstInner, None);
                 } else {
-                    self.ecx().tcx.sess.delay_span_bug(
-                        rustc_span::DUMMY_SP,
-                        "vtables pointers cannot be integer pointers",
-                    );
+                    // Let validation show the error message, but make sure it *does* error.
+                    tcx.sess
+                        .delay_span_bug(tcx.span, "vtables pointers cannot be integer pointers");
                 }
             }
             // Check if we have encountered this pointer+layout combination before.
             // Only recurse for allocation-backed pointers.
             if let Scalar::Ptr(ptr) = mplace.ptr {
-                // We do not have any `frozen` logic here, because it's essentially equivalent to
-                // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze",
-                // and we check that in `visit_aggregate`.
-                // This is not an inherent limitation, but one that we know to be true, because
-                // const qualification enforces it. We can lift it in the future.
-                match (self.mode, mutability) {
-                    // immutable references are fine everywhere
-                    (_, hir::Mutability::Not) => {}
-                    // all is "good and well" in the unsoundness of `static mut`
+                // Compute the mode with which we intern this.
+                let ref_mode = match self.mode {
+                    InternMode::Static(mutbl) => {
+                        // In statics, merge outer mutability with reference mutability and
+                        // take into account whether we are in an `UnsafeCell`.
 
-                    // mutable references are ok in `static`. Either they are treated as immutable
-                    // because they are behind an immutable one, or they are behind an `UnsafeCell`
-                    // and thus ok.
-                    (InternMode::Static, hir::Mutability::Mut) => {}
-                    // we statically prevent `&mut T` via `const_qualif` and double check this here
-                    (InternMode::ConstBase | InternMode::Const, hir::Mutability::Mut) => {
-                        match referenced_ty.kind {
-                            ty::Array(_, n)
-                                if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {}
-                            ty::Slice(_)
-                                if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? == 0 => {}
-                            _ => bug!("const qualif failed to prevent mutable references"),
+                        // The only way a mutable reference actually works as a mutable reference is
+                        // by being in a `static mut` directly or behind another mutable reference.
+                        // If there's an immutable reference or we are inside a `static`, then our
+                        // mutable reference is equivalent to an immutable one. As an example:
+                        // `&&mut Foo` is semantically equivalent to `&&Foo`
+                        match ref_mutability {
+                            _ if self.inside_unsafe_cell => {
+                                // Inside an `UnsafeCell` is like inside a `static mut`, the "outer"
+                                // mutability does not matter.
+                                InternMode::Static(ref_mutability)
+                            }
+                            Mutability::Not => {
+                                // A shared reference, things become immutable.
+                                // We do *not* consier `freeze` here -- that is done more precisely
+                                // when traversing the referenced data (by tracking `UnsafeCell`).
+                                InternMode::Static(Mutability::Not)
+                            }
+                            Mutability::Mut => {
+                                // Mutable reference.
+                                InternMode::Static(mutbl)
+                            }
                         }
                     }
-                }
-                // Compute the mutability with which we'll start visiting the allocation. This is
-                // what gets changed when we encounter an `UnsafeCell`.
-                //
-                // The only way a mutable reference actually works as a mutable reference is
-                // by being in a `static mut` directly or behind another mutable reference.
-                // If there's an immutable reference or we are inside a static, then our
-                // mutable reference is equivalent to an immutable one. As an example:
-                // `&&mut Foo` is semantically equivalent to `&&Foo`
-                let mutability = self.mutability.and(mutability);
-                // Recursing behind references changes the intern mode for constants in order to
-                // cause assertions to trigger if we encounter any `UnsafeCell`s.
-                let mode = match self.mode {
-                    InternMode::ConstBase => InternMode::Const,
-                    other => other,
+                    InternMode::ConstBase | InternMode::ConstInner => {
+                        // Ignore `UnsafeCell`, everything is immutable.  Do some sanity checking
+                        // for mutable references that we encounter -- they must all be ZST.
+                        // This helps to prevent users from accidentally exploiting UB that they
+                        // caused (by somehow getting a mutable reference in a `const`).
+                        if ref_mutability == Mutability::Mut {
+                            match referenced_ty.kind {
+                                ty::Array(_, n)
+                                    if n.eval_usize(tcx.tcx, self.ecx.param_env) == 0 => {}
+                                ty::Slice(_)
+                                    if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)?
+                                        == 0 => {}
+                                _ => mutable_memory_in_const(tcx, "`&mut`"),
+                            }
+                        } else {
+                            // A shared reference. We cannot check `freeze` here due to references
+                            // like `&dyn Trait` that are actually immutable.  We do check for
+                            // concrete `UnsafeCell` when traversing the pointee though (if it is
+                            // a new allocation, not yet interned).
+                        }
+                        // Go on with the "inner" rules.
+                        InternMode::ConstInner
+                    }
                 };
-                match self.intern_shallow(ptr.alloc_id, mutability, Some(mplace.layout.ty))? {
+                match self.intern_shallow(ptr.alloc_id, ref_mode, Some(referenced_ty)) {
                     // No need to recurse, these are interned already and statics may have
                     // cycles, so we don't want to recurse there
                     Some(IsStaticOrFn) => {}
                     // intern everything referenced by this value. The mutability is taken from the
                     // reference. It is checked above that mutable references only happen in
                     // `static mut`
-                    None => self.ref_tracking.track((mplace, mutability, mode), || ()),
+                    None => self.ref_tracking.track((mplace, ref_mode), || ()),
                 }
             }
             Ok(())
@@ -273,6 +288,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
 pub enum InternKind {
     /// The `mutability` of the static, ignoring the type which may have interior mutability.
     Static(hir::Mutability),
@@ -281,71 +297,78 @@ pub enum InternKind {
     ConstProp,
 }
 
+/// Intern `ret` and everything it references.
+///
+/// This *cannot raise an interpreter error*.  Doing so is left to validation, which
+/// tracks where in the value we are and thus can show much better error messages.
+/// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
+/// are hard errors.
 pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
     ecx: &mut InterpCx<'mir, 'tcx, M>,
     intern_kind: InternKind,
     ret: MPlaceTy<'tcx>,
-    ignore_interior_mut_in_const_validation: bool,
-) -> InterpResult<'tcx>
-where
+    ignore_interior_mut_in_const: bool,
+) where
     'tcx: 'mir,
 {
     let tcx = ecx.tcx;
-    let (base_mutability, base_intern_mode) = match intern_kind {
-        // `static mut` doesn't care about interior mutability, it's mutable anyway
-        InternKind::Static(mutbl) => (mutbl, InternMode::Static),
+    let base_intern_mode = match intern_kind {
+        InternKind::Static(mutbl) => InternMode::Static(mutbl),
         // FIXME: what about array lengths, array initializers?
-        InternKind::Constant | InternKind::ConstProp => (Mutability::Not, InternMode::ConstBase),
-        InternKind::Promoted => (Mutability::Not, InternMode::ConstBase),
+        InternKind::Constant | InternKind::ConstProp | InternKind::Promoted => {
+            InternMode::ConstBase
+        }
     };
 
     // Type based interning.
-    // `ref_tracking` tracks typed references we have seen and still need to crawl for
+    // `ref_tracking` tracks typed references we have already interned and still need to crawl for
     // more typed information inside them.
     // `leftover_allocations` collects *all* allocations we see, because some might not
     // be available in a typed way. They get interned at the end.
-    let mut ref_tracking = RefTracking::new((ret, base_mutability, base_intern_mode));
+    let mut ref_tracking = RefTracking::empty();
     let leftover_allocations = &mut FxHashSet::default();
 
     // start with the outermost allocation
     intern_shallow(
         ecx,
         leftover_allocations,
-        base_intern_mode,
         // The outermost allocation must exist, because we allocated it with
         // `Memory::allocate`.
         ret.ptr.assert_ptr().alloc_id,
-        base_mutability,
+        base_intern_mode,
         Some(ret.layout.ty),
-    )?;
+    );
 
-    while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
-        let interned = InternVisitor {
+    ref_tracking.track((ret, base_intern_mode), || ());
+
+    while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
+        let res = InternVisitor {
             ref_tracking: &mut ref_tracking,
             ecx,
             mode,
             leftover_allocations,
-            mutability,
-            ignore_interior_mut_in_const_validation,
+            ignore_interior_mut_in_const,
+            inside_unsafe_cell: false,
         }
         .visit_value(mplace);
-        if let Err(error) = interned {
-            // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
-            // to read enum discriminants in order to find references in enum variant fields.
-            if let err_ub!(ValidationFailure(_)) = error.kind {
-                let err = crate::const_eval::error_to_const_error(&ecx, error);
-                match err.struct_error(
-                    ecx.tcx,
-                    "it is undefined behavior to use this value",
-                    |mut diag| {
-                        diag.note(crate::const_eval::note_on_undefined_behavior_error());
-                        diag.emit();
-                    },
-                ) {
-                    ErrorHandled::TooGeneric
-                    | ErrorHandled::Reported(ErrorReported)
-                    | ErrorHandled::Linted => {}
-                }
+        // We deliberately *ignore* interpreter errors here.  When there is a problem, the remaining
+        // references are "leftover"-interned, and later validation will show a proper error
+        // and point at the right part of the value causing the problem.
+        match res {
+            Ok(()) => {}
+            Err(error) => {
+                ecx.tcx.sess.delay_span_bug(
+                    ecx.tcx.span,
+                    "error during interning should later cause validation failure",
+                );
+                // 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.
+                assert!(
+                    !error.kind.allocates(),
+                    "interning encountered allocating error: {}",
+                    error
+                );
             }
         }
     }
@@ -366,26 +389,27 @@ where
                 InternKind::Static(_) => {}
                 // Raw pointers in promoteds may only point to immutable things so we mark
                 // everything as immutable.
-                // It is UB to mutate through a raw pointer obtained via an immutable reference.
+                // It is UB to mutate through a raw pointer obtained via an immutable reference:
                 // Since all references and pointers inside a promoted must by their very definition
                 // be created from an immutable reference (and promotion also excludes interior
                 // mutability), mutating through them would be UB.
                 // There's no way we can check whether the user is using raw pointers correctly,
                 // so all we can do is mark this as immutable here.
                 InternKind::Promoted => {
+                    // See const_eval::machine::MemoryExtra::can_access_statics for why
+                    // immutability is so important.
                     alloc.mutability = Mutability::Not;
                 }
                 InternKind::Constant | InternKind::ConstProp => {
-                    // If it's a constant, it *must* be immutable.
-                    // We cannot have mutable memory inside a constant.
-                    // We use `delay_span_bug` here, because this can be reached in the presence
-                    // of fancy transmutes.
-                    if alloc.mutability == Mutability::Mut {
-                        // For better errors later, mark the allocation as immutable
-                        // (on top of the delayed ICE).
-                        alloc.mutability = Mutability::Not;
-                        ecx.tcx.sess.delay_span_bug(ecx.tcx.span, "mutable allocation in constant");
-                    }
+                    // If it's a constant, we should not have any "leftovers" as everything
+                    // is tracked by const-checking.
+                    // FIXME: downgrade this to a warning? It rejects some legitimate consts,
+                    // such as `const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _;`.
+                    ecx.tcx
+                        .sess
+                        .span_err(ecx.tcx.span, "untyped pointers are not allowed in constant");
+                    // For better errors later, mark the allocation as immutable.
+                    alloc.mutability = Mutability::Not;
                 }
             }
             let alloc = tcx.intern_const_alloc(alloc);
@@ -396,13 +420,13 @@ where
                 }
             }
         } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) {
-            // dangling pointer
-            throw_ub_format!("encountered dangling pointer in final constant")
+            // Codegen does not like dangling pointers, and generally `tcx` assumes that
+            // all allocations referenced anywhere actually exist. So, make sure we error here.
+            ecx.tcx.sess.span_err(ecx.tcx.span, "encountered dangling pointer in final constant");
         } else if ecx.tcx.get_global_alloc(alloc_id).is_none() {
-            // We have hit an `AllocId` that is neither in local or global memory and isn't marked
-            // as dangling by local memory.
+            // We have hit an `AllocId` that is neither in local or global memory and isn't
+            // marked as dangling by local memory.  That should be impossible.
             span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id);
         }
     }
-    Ok(())
 }
diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs
index b81a454cac4..71cca725982 100644
--- a/src/librustc_mir/interpret/intrinsics/type_name.rs
+++ b/src/librustc_mir/interpret/intrinsics/type_name.rs
@@ -60,7 +60,6 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
             | ty::FnDef(def_id, substs)
             | ty::Opaque(def_id, substs)
             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
-            | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs })
             | ty::Closure(def_id, substs)
             | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 4f90f83b735..f6020641d3e 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, LayoutOf, Scalar, VariantIdx, Variants};
+use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx, Variants};
 
 use std::hash::Hash;
 
@@ -566,7 +566,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             | ty::Bound(..)
             | ty::Param(..)
             | ty::Opaque(..)
-            | ty::UnnormalizedProjection(..)
             | ty::Projection(..)
             | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty),
         }
@@ -744,10 +743,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         match op.layout.ty.kind {
             ty::Str => {
                 let mplace = op.assert_mem_place(self.ecx); // strings are never immediate
+                let len = mplace.len(self.ecx)?;
                 try_validation!(
-                    self.ecx.read_str(mplace),
+                    self.ecx.memory.read_bytes(mplace.ptr, Size::from_bytes(len)),
                     self.path,
-                    err_ub!(InvalidStr(..)) => { "uninitialized or non-UTF-8 data in str" },
+                    err_ub!(InvalidUninitBytes(..)) => { "uninitialized data in `str`" },
                 );
             }
             ty::Array(tys, ..) | ty::Slice(tys)
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 09f8588cee2..785c6c21d74 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -19,7 +19,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(exhaustive_patterns)]
 #![feature(iter_order_by)]
 #![feature(never_type)]
-#![feature(specialization)]
+#![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
 #![feature(associated_type_bounds)]
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 4648100e3b7..a8094990594 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -580,10 +580,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             }
             mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => {
                 let tcx = self.tcx;
-                let exchange_malloc_fn_def_id = tcx
-                    .lang_items()
-                    .require(ExchangeMallocFnLangItem)
-                    .unwrap_or_else(|e| tcx.sess.fatal(&e));
+                let exchange_malloc_fn_def_id =
+                    tcx.require_lang_item(ExchangeMallocFnLangItem, None);
                 let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
                 if should_monomorphize_locally(tcx, &instance) {
                     self.output.push(create_fn_mono_item(instance));
diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs
index 98a3d9584f5..28edd87a3ad 100644
--- a/src/librustc_mir/monomorphize/mod.rs
+++ b/src/librustc_mir/monomorphize/mod.rs
@@ -2,6 +2,8 @@ use rustc_middle::traits;
 use rustc_middle::ty::adjustment::CustomCoerceUnsized;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
+use rustc_hir::lang_items::CoerceUnsizedTraitLangItem;
+
 pub mod collector;
 pub mod partitioning;
 
@@ -10,7 +12,7 @@ pub fn custom_coerce_unsize_info<'tcx>(
     source_ty: Ty<'tcx>,
     target_ty: Ty<'tcx>,
 ) -> CustomCoerceUnsized {
-    let def_id = tcx.lang_items().coerce_unsized_trait().unwrap();
+    let def_id = tcx.require_lang_item(CoerceUnsizedTraitLangItem, None);
 
     let trait_ref = ty::Binder::bind(ty::TraitRef {
         def_id,
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 847f59b95e9..d025468d28b 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -1,5 +1,6 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::FnMutTraitLangItem;
 use rustc_middle::mir::*;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
@@ -70,7 +71,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
             build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None)
         }
         ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
-            let fn_mut = tcx.lang_items().fn_mut_trait().unwrap();
+            let fn_mut = tcx.require_lang_item(FnMutTraitLangItem, None);
             let call_mut = tcx
                 .associated_items(fn_mut)
                 .in_definition_order()
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 4be95b69850..e1be1daca45 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -349,8 +349,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn get_const(&self, local: Local) -> Option<OpTy<'tcx>> {
-        let op = self.ecx.access_local(self.ecx.frame(), local, None).ok();
+    fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
+        let op = self.ecx.eval_place_to_op(place, None).ok();
 
         // Try to read the local as an immediate so that if it is representable as a scalar, we can
         // handle it as such, but otherwise, just return the value as is.
@@ -616,6 +616,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         value: OpTy<'tcx>,
         source_info: SourceInfo,
     ) {
+        if let Rvalue::Use(Operand::Constant(c)) = rval {
+            if !matches!(c.literal.val, ConstKind::Unevaluated(..)) {
+                trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
+                return;
+            }
+        }
+
         trace!("attepting to replace {:?} with {:?}", rval, value);
         if let Err(e) = self.ecx.const_validate_operand(
             value,
@@ -702,8 +709,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             )) => l.is_bits() && r.is_bits(),
             interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
                 let mplace = op.assert_mem_place(&self.ecx);
-                intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false)
-                    .expect("failed to intern alloc");
+                intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false);
                 true
             }
             _ => false,
@@ -772,13 +778,29 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::PlaceContext::*;
         match context {
-            // Constants must have at most one write
-            // FIXME(oli-obk): we could be more powerful here, if the multiple writes
-            // only occur in independent execution paths
-            MutatingUse(MutatingUseContext::Store) => {
+            // Projections are fine, because `&mut foo.x` will be caught by
+            // `MutatingUseContext::Borrow` elsewhere.
+            MutatingUse(MutatingUseContext::Projection)
+            // These are just stores, where the storing is not propagatable, but there may be later
+            // mutations of the same local via `Store`
+            | MutatingUse(MutatingUseContext::Call)
+            // Actual store that can possibly even propagate a value
+            | MutatingUse(MutatingUseContext::Store) => {
                 if !self.found_assignment.insert(local) {
-                    trace!("local {:?} can't be propagated because of multiple assignments", local);
-                    self.can_const_prop[local] = ConstPropMode::NoPropagation;
+                    match &mut self.can_const_prop[local] {
+                        // If the local can only get propagated in its own block, then we don't have
+                        // to worry about multiple assignments, as we'll nuke the const state at the
+                        // end of the block anyway, and inside the block we overwrite previous
+                        // states as applicable.
+                        ConstPropMode::OnlyInsideOwnBlock => {}
+                        other => {
+                            trace!(
+                                "local {:?} can't be propagated because of multiple assignments",
+                                local,
+                            );
+                            *other = ConstPropMode::NoPropagation;
+                        }
+                    }
                 }
             }
             // Reading constants is allowed an arbitrary number of times
@@ -787,13 +809,21 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
             | NonMutatingUse(NonMutatingUseContext::Inspect)
             | NonMutatingUse(NonMutatingUseContext::Projection)
             | NonUse(_) => {}
-            // FIXME(felix91gr): explain the reasoning behind this
-            MutatingUse(MutatingUseContext::Projection) => {
-                if self.local_kinds[local] != LocalKind::Temp {
-                    self.can_const_prop[local] = ConstPropMode::NoPropagation;
-                }
-            }
-            _ => {
+
+            // These could be propagated with a smarter analysis or just some careful thinking about
+            // whether they'd be fine right now.
+            MutatingUse(MutatingUseContext::AsmOutput)
+            | MutatingUse(MutatingUseContext::Yield)
+            | MutatingUse(MutatingUseContext::Drop)
+            | MutatingUse(MutatingUseContext::Retag)
+            // These can't ever be propagated under any scheme, as we can't reason about indirect
+            // mutation.
+            | NonMutatingUse(NonMutatingUseContext::SharedBorrow)
+            | NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
+            | NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
+            | NonMutatingUse(NonMutatingUseContext::AddressOf)
+            | MutatingUse(MutatingUseContext::Borrow)
+            | MutatingUse(MutatingUseContext::AddressOf) => {
                 trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
                 self.can_const_prop[local] = ConstPropMode::NoPropagation;
             }
@@ -826,40 +856,55 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
         if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
             let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
             if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
-                if let Some(local) = place.as_local() {
-                    let can_const_prop = self.can_const_prop[local];
-                    if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
-                        if can_const_prop != ConstPropMode::NoPropagation {
-                            // This will return None for Locals that are from other blocks,
-                            // so it should be okay to propagate from here on down.
-                            if let Some(value) = self.get_const(local) {
-                                if self.should_const_prop(value) {
-                                    trace!("replacing {:?} with {:?}", rval, value);
-                                    self.replace_with_const(rval, value, statement.source_info);
-                                    if can_const_prop == ConstPropMode::FullConstProp
-                                        || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
-                                    {
-                                        trace!("propagated into {:?}", local);
-                                    }
-                                }
-                                if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
-                                    trace!(
-                                        "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
-                                        local
-                                    );
-                                    self.locals_of_current_block.insert(local);
+                let can_const_prop = self.can_const_prop[place.local];
+                if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
+                    if can_const_prop != ConstPropMode::NoPropagation {
+                        // This will return None for variables that are from other blocks,
+                        // so it should be okay to propagate from here on down.
+                        if let Some(value) = self.get_const(place) {
+                            if self.should_const_prop(value) {
+                                trace!("replacing {:?} with {:?}", rval, value);
+                                self.replace_with_const(rval, value, statement.source_info);
+                                if can_const_prop == ConstPropMode::FullConstProp
+                                    || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+                                {
+                                    trace!("propagated into {:?}", place);
                                 }
                             }
+                            if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
+                                trace!(
+                                    "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
+                                    place.local
+                                );
+                                self.locals_of_current_block.insert(place.local);
+                            }
                         }
                     }
-                    if self.can_const_prop[local] == ConstPropMode::OnlyPropagateInto
-                        || self.can_const_prop[local] == ConstPropMode::NoPropagation
+                    if can_const_prop == ConstPropMode::OnlyPropagateInto
+                        || can_const_prop == ConstPropMode::NoPropagation
                     {
-                        trace!("can't propagate into {:?}", local);
-                        if local != RETURN_PLACE {
-                            Self::remove_const(&mut self.ecx, local);
+                        trace!("can't propagate into {:?}", place);
+                        if place.local != RETURN_PLACE {
+                            Self::remove_const(&mut self.ecx, place.local);
                         }
                     }
+                } else {
+                    // Const prop failed, so erase the destination, ensuring that whatever happens
+                    // from here on, does not know about the previous value.
+                    // This is important in case we have
+                    // ```rust
+                    // let mut x = 42;
+                    // x = SOME_MUTABLE_STATIC;
+                    // // x must now be undefined
+                    // ```
+                    // FIXME: we overzealously erase the entire local, because that's easier to
+                    // implement.
+                    trace!(
+                        "propagation into {:?} failed.
+                        Nuking the entire site from orbit, it's the only way to be sure",
+                        place,
+                    );
+                    Self::remove_const(&mut self.ecx, place.local);
                 }
             }
         } else {
@@ -993,7 +1038,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                           arguments are of the variant `Operand::Copy`. This allows us to
                           simplify our handling of `Operands` in this case.
                         */
-                        if let Some(l) = opr.place().and_then(|p| p.as_local()) {
+                        if let Some(l) = opr.place() {
                             if let Some(value) = self.get_const(l) {
                                 if self.should_const_prop(value) {
                                     // FIXME(felix91gr): this code only handles `Scalar` cases.
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index b9eb58f800e..ba406c72df8 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -73,7 +73,12 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
                     }
                     // Conservatively gives up if the dest is an argument,
                     // because there may be uses of the original argument value.
-                    if body.local_kind(dest_local) == LocalKind::Arg {
+                    // Also gives up on the return place, as we cannot propagate into its implicit
+                    // use by `return`.
+                    if matches!(
+                        body.local_kind(dest_local),
+                        LocalKind::Arg | LocalKind::ReturnPointer
+                    ) {
                         debug!("  Can't copy-propagate local: dest {:?} (argument)", dest_local);
                         continue;
                     }
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index d334006d7b5..14faa5be02f 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -61,6 +61,7 @@ use crate::util::storage;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::{GeneratorStateLangItem, PinTypeLangItem};
 use rustc_index::bit_set::{BitMatrix, BitSet};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
@@ -91,6 +92,16 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
             *local = self.to;
         }
     }
+
+    fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) {
+        match kind {
+            TerminatorKind::Return => {
+                // Do not replace the implicit `_0` access here, as that's not possible. The
+                // transform already handles `return` correctly.
+            }
+            _ => self.super_terminator_kind(kind, location),
+        }
+    }
 }
 
 struct DerefArgVisitor<'tcx> {
@@ -371,7 +382,7 @@ fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo
 fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let ref_gen_ty = body.local_decls.raw[1].ty;
 
-    let pin_did = tcx.lang_items().pin_type().unwrap();
+    let pin_did = tcx.require_lang_item(PinTypeLangItem, Some(body.span));
     let pin_adt_ref = tcx.adt_def(pin_did);
     let substs = tcx.intern_substs(&[ref_gen_ty.into()]);
     let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs);
@@ -1197,7 +1208,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         };
 
         // Compute GeneratorState<yield_ty, return_ty>
-        let state_did = tcx.lang_items().gen_state().unwrap();
+        let state_did = tcx.require_lang_item(GeneratorStateLangItem, None);
         let state_adt_ref = tcx.adt_def(state_did);
         let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]);
         let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index a8e949ecb31..632408fde74 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -732,7 +732,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
     }
 
     fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, loc: Location) {
-        self.super_terminator_kind(kind, loc);
+        // Don't try to modify the implicit `_0` access on return (`return` terminators are
+        // replaced down below anyways).
+        if !matches!(kind, TerminatorKind::Return) {
+            self.super_terminator_kind(kind, loc);
+        }
 
         match *kind {
             TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => bug!(),
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 220691c1570..7ad5baac205 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -317,12 +317,12 @@ fn run_optimization_passes<'tcx>(
         //   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,
         &simplify_branches::SimplifyBranches::new("after-copy-prop"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &simplify::SimplifyCfg::new("after-remove-noop-landing-pads"),
-        &simplify_try::SimplifyArmIdentity,
-        &simplify_try::SimplifyBranchSame,
         &simplify::SimplifyCfg::new("final"),
         &simplify::SimplifyLocals,
     ];
diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs
index d22c2d90600..41ffa659441 100644
--- a/src/librustc_mir/transform/simplify_try.rs
+++ b/src/librustc_mir/transform/simplify_try.rs
@@ -11,9 +11,12 @@
 
 use crate::transform::{simplify, MirPass, MirSource};
 use itertools::Itertools as _;
+use rustc_index::vec::IndexVec;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
+use std::iter::{Enumerate, Peekable};
+use std::slice::Iter;
 
 /// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
 ///
@@ -21,7 +24,8 @@ use rustc_target::abi::VariantIdx;
 ///
 /// ```rust
 /// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
-/// ((_LOCAL_0 as Variant).FIELD: TY) = move _LOCAL_TMP;
+/// _TMP_2 = _LOCAL_TMP;
+/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2;
 /// discriminant(_LOCAL_0) = VAR_IDX;
 /// ```
 ///
@@ -32,50 +36,320 @@ use rustc_target::abi::VariantIdx;
 /// ```
 pub struct SimplifyArmIdentity;
 
+#[derive(Debug)]
+struct ArmIdentityInfo<'tcx> {
+    /// Storage location for the variant's field
+    local_temp_0: Local,
+    /// Storage location holding the variant being read from
+    local_1: Local,
+    /// The variant field being read from
+    vf_s0: VarField<'tcx>,
+    /// Index of the statement which loads the variant being read
+    get_variant_field_stmt: usize,
+
+    /// Tracks each assignment to a temporary of the variant's field
+    field_tmp_assignments: Vec<(Local, Local)>,
+
+    /// Storage location holding the variant's field that was read from
+    local_tmp_s1: Local,
+    /// Storage location holding the enum that we are writing to
+    local_0: Local,
+    /// The variant field being written to
+    vf_s1: VarField<'tcx>,
+
+    /// Storage location that the discriminant is being written to
+    set_discr_local: Local,
+    /// The variant being written
+    set_discr_var_idx: VariantIdx,
+
+    /// Index of the statement that should be overwritten as a move
+    stmt_to_overwrite: usize,
+    /// SourceInfo for the new move
+    source_info: SourceInfo,
+
+    /// Indices of matching Storage{Live,Dead} statements encountered.
+    /// (StorageLive index,, StorageDead index, Local)
+    storage_stmts: Vec<(usize, usize, Local)>,
+
+    /// The statements that should be removed (turned into nops)
+    stmts_to_remove: Vec<usize>,
+}
+
+fn get_arm_identity_info<'a, 'tcx>(stmts: &'a [Statement<'tcx>]) -> Option<ArmIdentityInfo<'tcx>> {
+    // This can't possibly match unless there are at least 3 statements in the block
+    // so fail fast on tiny blocks.
+    if stmts.len() < 3 {
+        return None;
+    }
+
+    let mut tmp_assigns = Vec::new();
+    let mut nop_stmts = Vec::new();
+    let mut storage_stmts = Vec::new();
+    let mut storage_live_stmts = Vec::new();
+    let mut storage_dead_stmts = Vec::new();
+
+    type StmtIter<'a, 'tcx> = Peekable<Enumerate<Iter<'a, Statement<'tcx>>>>;
+
+    fn is_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
+        matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_))
+    }
+
+    /// Eats consecutive Statements which match `test`, performing the specified `action` for each.
+    /// The iterator `stmt_iter` is not advanced if none were matched.
+    fn try_eat<'a, 'tcx>(
+        stmt_iter: &mut StmtIter<'a, 'tcx>,
+        test: impl Fn(&'a Statement<'tcx>) -> bool,
+        mut action: impl FnMut(usize, &'a Statement<'tcx>) -> (),
+    ) {
+        while stmt_iter.peek().map(|(_, stmt)| test(stmt)).unwrap_or(false) {
+            let (idx, stmt) = stmt_iter.next().unwrap();
+
+            action(idx, stmt);
+        }
+    }
+
+    /// Eats consecutive `StorageLive` and `StorageDead` Statements.
+    /// The iterator `stmt_iter` is not advanced if none were found.
+    fn try_eat_storage_stmts<'a, 'tcx>(
+        stmt_iter: &mut StmtIter<'a, 'tcx>,
+        storage_live_stmts: &mut Vec<(usize, Local)>,
+        storage_dead_stmts: &mut Vec<(usize, Local)>,
+    ) {
+        try_eat(stmt_iter, is_storage_stmt, |idx, stmt| {
+            if let StatementKind::StorageLive(l) = stmt.kind {
+                storage_live_stmts.push((idx, l));
+            } else if let StatementKind::StorageDead(l) = stmt.kind {
+                storage_dead_stmts.push((idx, l));
+            }
+        })
+    }
+
+    fn is_tmp_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
+        use rustc_middle::mir::StatementKind::Assign;
+        if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind {
+            place.as_local().is_some() && p.as_local().is_some()
+        } else {
+            false
+        }
+    }
+
+    /// Eats consecutive `Assign` Statements.
+    // The iterator `stmt_iter` is not advanced if none were found.
+    fn try_eat_assign_tmp_stmts<'a, 'tcx>(
+        stmt_iter: &mut StmtIter<'a, 'tcx>,
+        tmp_assigns: &mut Vec<(Local, Local)>,
+        nop_stmts: &mut Vec<usize>,
+    ) {
+        try_eat(stmt_iter, is_tmp_storage_stmt, |idx, stmt| {
+            use rustc_middle::mir::StatementKind::Assign;
+            if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) =
+                &stmt.kind
+            {
+                tmp_assigns.push((place.as_local().unwrap(), p.as_local().unwrap()));
+                nop_stmts.push(idx);
+            }
+        })
+    }
+
+    fn find_storage_live_dead_stmts_for_local<'tcx>(
+        local: Local,
+        stmts: &[Statement<'tcx>],
+    ) -> Option<(usize, usize)> {
+        trace!("looking for {:?}", local);
+        let mut storage_live_stmt = None;
+        let mut storage_dead_stmt = None;
+        for (idx, stmt) in stmts.iter().enumerate() {
+            if stmt.kind == StatementKind::StorageLive(local) {
+                storage_live_stmt = Some(idx);
+            } else if stmt.kind == StatementKind::StorageDead(local) {
+                storage_dead_stmt = Some(idx);
+            }
+        }
+
+        Some((storage_live_stmt?, storage_dead_stmt.unwrap_or(usize::MAX)))
+    }
+
+    // Try to match the expected MIR structure with the basic block we're processing.
+    // We want to see something that looks like:
+    // ```
+    // (StorageLive(_) | StorageDead(_));*
+    // _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
+    // (StorageLive(_) | StorageDead(_));*
+    // (tmp_n+1 = tmp_n);*
+    // (StorageLive(_) | StorageDead(_));*
+    // (tmp_n+1 = tmp_n);*
+    // ((LOCAL_FROM as Variant).FIELD: TY) = move tmp;
+    // discriminant(LOCAL_FROM) = VariantIdx;
+    // (StorageLive(_) | StorageDead(_));*
+    // ```
+    let mut stmt_iter = stmts.iter().enumerate().peekable();
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    let (get_variant_field_stmt, stmt) = stmt_iter.next()?;
+    let (local_tmp_s0, local_1, vf_s0) = match_get_variant_field(stmt)?;
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
+
+    let (idx, stmt) = stmt_iter.next()?;
+    let (local_tmp_s1, local_0, vf_s1) = match_set_variant_field(stmt)?;
+    nop_stmts.push(idx);
+
+    let (idx, stmt) = stmt_iter.next()?;
+    let (set_discr_local, set_discr_var_idx) = match_set_discr(stmt)?;
+    let discr_stmt_source_info = stmt.source_info;
+    nop_stmts.push(idx);
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    for (live_idx, live_local) in storage_live_stmts {
+        if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) {
+            let (dead_idx, _) = storage_dead_stmts.swap_remove(i);
+            storage_stmts.push((live_idx, dead_idx, live_local));
+
+            if live_local == local_tmp_s0 {
+                nop_stmts.push(get_variant_field_stmt);
+            }
+        }
+    }
+
+    nop_stmts.sort();
+
+    // Use one of the statements we're going to discard between the point
+    // where the storage location for the variant field becomes live and
+    // is killed.
+    let (live_idx, dead_idx) = find_storage_live_dead_stmts_for_local(local_tmp_s0, stmts)?;
+    let stmt_to_overwrite =
+        nop_stmts.iter().find(|stmt_idx| live_idx < **stmt_idx && **stmt_idx < dead_idx);
+
+    Some(ArmIdentityInfo {
+        local_temp_0: local_tmp_s0,
+        local_1,
+        vf_s0,
+        get_variant_field_stmt,
+        field_tmp_assignments: tmp_assigns,
+        local_tmp_s1,
+        local_0,
+        vf_s1,
+        set_discr_local,
+        set_discr_var_idx,
+        stmt_to_overwrite: *stmt_to_overwrite?,
+        source_info: discr_stmt_source_info,
+        storage_stmts,
+        stmts_to_remove: nop_stmts,
+    })
+}
+
+fn optimization_applies<'tcx>(
+    opt_info: &ArmIdentityInfo<'tcx>,
+    local_decls: &IndexVec<Local, LocalDecl<'tcx>>,
+) -> bool {
+    trace!("testing if optimization applies...");
+
+    // FIXME(wesleywiser): possibly relax this restriction?
+    if opt_info.local_0 == opt_info.local_1 {
+        trace!("NO: moving into ourselves");
+        return false;
+    } else if opt_info.vf_s0 != opt_info.vf_s1 {
+        trace!("NO: the field-and-variant information do not match");
+        return false;
+    } else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty {
+        // FIXME(Centril,oli-obk): possibly relax to same layout?
+        trace!("NO: source and target locals have different types");
+        return false;
+    } else if (opt_info.local_0, opt_info.vf_s0.var_idx)
+        != (opt_info.set_discr_local, opt_info.set_discr_var_idx)
+    {
+        trace!("NO: the discriminants do not match");
+        return false;
+    }
+
+    // Verify the assigment chain consists of the form b = a; c = b; d = c; etc...
+    if opt_info.field_tmp_assignments.len() == 0 {
+        trace!("NO: no assignments found");
+    }
+    let mut last_assigned_to = opt_info.field_tmp_assignments[0].1;
+    let source_local = last_assigned_to;
+    for (l, r) in &opt_info.field_tmp_assignments {
+        if *r != last_assigned_to {
+            trace!("NO: found unexpected assignment {:?} = {:?}", l, r);
+            return false;
+        }
+
+        last_assigned_to = *l;
+    }
+
+    if source_local != opt_info.local_temp_0 {
+        trace!(
+            "NO: start of assignment chain does not match enum variant temp: {:?} != {:?}",
+            source_local,
+            opt_info.local_temp_0
+        );
+        return false;
+    } else if last_assigned_to != opt_info.local_tmp_s1 {
+        trace!(
+            "NO: end of assignemnt chain does not match written enum temp: {:?} != {:?}",
+            last_assigned_to,
+            opt_info.local_tmp_s1
+        );
+        return false;
+    }
+
+    trace!("SUCCESS: optimization applies!");
+    return true;
+}
+
 impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
-    fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+        trace!("running SimplifyArmIdentity on {:?}", source);
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         for bb in basic_blocks {
-            // Need 3 statements:
-            let (s0, s1, s2) = match &mut *bb.statements {
-                [s0, s1, s2] => (s0, s1, s2),
-                _ => continue,
-            };
+            if let Some(opt_info) = get_arm_identity_info(&bb.statements) {
+                trace!("got opt_info = {:#?}", opt_info);
+                if !optimization_applies(&opt_info, local_decls) {
+                    debug!("optimization skipped for {:?}", source);
+                    continue;
+                }
 
-            // Pattern match on the form we want:
-            let (local_tmp_s0, local_1, vf_s0) = match match_get_variant_field(s0) {
-                None => continue,
-                Some(x) => x,
-            };
-            let (local_tmp_s1, local_0, vf_s1) = match match_set_variant_field(s1) {
-                None => continue,
-                Some(x) => x,
-            };
-            if local_tmp_s0 != local_tmp_s1
-                // Avoid moving into ourselves.
-                || local_0 == local_1
-                // The field-and-variant information match up.
-                || vf_s0 != vf_s1
-                // Source and target locals have the same type.
-                // FIXME(Centril | oli-obk): possibly relax to same layout?
-                || local_decls[local_0].ty != local_decls[local_1].ty
-                // We're setting the discriminant of `local_0` to this variant.
-                || Some((local_0, vf_s0.var_idx)) != match_set_discr(s2)
-            {
-                continue;
-            }
+                // Also remove unused Storage{Live,Dead} statements which correspond
+                // to temps used previously.
+                for (live_idx, dead_idx, local) in &opt_info.storage_stmts {
+                    // The temporary that we've read the variant field into is scoped to this block,
+                    // so we can remove the assignment.
+                    if *local == opt_info.local_temp_0 {
+                        bb.statements[opt_info.get_variant_field_stmt].make_nop();
+                    }
 
-            // Right shape; transform!
-            s0.source_info = s2.source_info;
-            match &mut s0.kind {
-                StatementKind::Assign(box (place, rvalue)) => {
-                    *place = local_0.into();
-                    *rvalue = Rvalue::Use(Operand::Move(local_1.into()));
+                    for (left, right) in &opt_info.field_tmp_assignments {
+                        if local == left || local == right {
+                            bb.statements[*live_idx].make_nop();
+                            bb.statements[*dead_idx].make_nop();
+                        }
+                    }
                 }
-                _ => unreachable!(),
+
+                // Right shape; transform
+                for stmt_idx in opt_info.stmts_to_remove {
+                    bb.statements[stmt_idx].make_nop();
+                }
+
+                let stmt = &mut bb.statements[opt_info.stmt_to_overwrite];
+                stmt.source_info = opt_info.source_info;
+                stmt.kind = StatementKind::Assign(box (
+                    opt_info.local_0.into(),
+                    Rvalue::Use(Operand::Move(opt_info.local_1.into())),
+                ));
+
+                bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop);
+
+                trace!("block is now {:?}", bb.statements);
             }
-            s1.make_nop();
-            s2.make_nop();
         }
     }
 }
@@ -129,7 +403,7 @@ fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)>
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
 struct VarField<'tcx> {
     field: Field,
     field_ty: Ty<'tcx>,
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 2d7d3a0ccae..af7c88b178d 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -1,6 +1,6 @@
 use crate::util::patch::MirPatch;
 use rustc_hir as hir;
-use rustc_hir::lang_items;
+use rustc_hir::lang_items::{BoxFreeFnLangItem, DropTraitLangItem};
 use rustc_index::vec::Idx;
 use rustc_middle::mir::*;
 use rustc_middle::traits::Reveal;
@@ -535,7 +535,7 @@ where
     fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock {
         debug!("destructor_call_block({:?}, {:?})", self, succ);
         let tcx = self.tcx();
-        let drop_trait = tcx.lang_items().drop_trait().unwrap();
+        let drop_trait = tcx.require_lang_item(DropTraitLangItem, None);
         let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap();
         let ty = self.place_ty(self.place);
         let substs = tcx.mk_substs_trait(ty, &[]);
@@ -877,8 +877,7 @@ where
     ) -> BasicBlock {
         let tcx = self.tcx();
         let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
-        let free_func =
-            tcx.require_lang_item(lang_items::BoxFreeFnLangItem, Some(self.source_info.span));
+        let free_func = tcx.require_lang_item(BoxFreeFnLangItem, Some(self.source_info.span));
         let args = adt.variants[VariantIdx::new(0)]
             .fields
             .iter()
diff --git a/src/librustc_mir_build/build/scope.rs b/src/librustc_mir_build/build/scope.rs
index 710a41bc8fd..19b983018c9 100644
--- a/src/librustc_mir_build/build/scope.rs
+++ b/src/librustc_mir_build/build/scope.rs
@@ -223,7 +223,7 @@ impl Scope {
     }
 }
 
-/// A trait that determined how [DropTree::lower_to_mir] creates its blocks and
+/// A trait that determined how [DropTree::build_mir] creates its blocks and
 /// links to any entry nodes.
 trait DropTreeBuilder<'tcx> {
     /// Create a new block for the tree. This should call either
diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs
index 0f22288437c..65ff311d182 100644
--- a/src/librustc_mir_build/hair/pattern/check_match.rs
+++ b/src/librustc_mir_build/hair/pattern/check_match.rs
@@ -246,7 +246,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
             );
         }
 
-        adt_defined_here(&mut cx, &mut err, pattern_ty, &witnesses);
+        adt_defined_here(&cx, &mut err, pattern_ty, &witnesses);
         err.note(&format!("the matched value is of type `{}`", pattern_ty));
         err.emit();
     }
diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs
index 4cc6a27a6da..28ec2ca13d5 100644
--- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs
+++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs
@@ -1,4 +1,5 @@
 use rustc_hir as hir;
+use rustc_hir::lang_items::EqTraitLangItem;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::Field;
@@ -121,7 +122,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                         )
                     }
                     traits::NonStructuralMatchTy::Dynamic => {
-                        format!("trait objects cannot be used in patterns")
+                        "trait objects cannot be used in patterns".to_string()
                     }
                     traits::NonStructuralMatchTy::Param => {
                         bug!("use of constant whose type is a parameter inside a pattern")
@@ -140,7 +141,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 // code at the moment, because types like `for <'a> fn(&'a ())` do
                 // not *yet* implement `PartialEq`. So for now we leave this here.
                 let ty_is_partial_eq: bool = {
-                    let partial_eq_trait_id = self.tcx().lang_items().eq_trait().unwrap();
+                    let partial_eq_trait_id =
+                        self.tcx().require_lang_item(EqTraitLangItem, Some(self.span));
                     let obligation: PredicateObligation<'_> = predicate_for_trait_def(
                         self.tcx(),
                         self.param_env,
diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs
index f676a34a1d1..2b7d5e5adb4 100644
--- a/src/librustc_parse/lexer/mod.rs
+++ b/src/librustc_parse/lexer/mod.rs
@@ -15,6 +15,7 @@ mod tokentrees;
 mod unescape_error_reporting;
 mod unicode_chars;
 
+use rustc_lexer::unescape::Mode;
 use unescape_error_reporting::{emit_unescape_error, push_escaped_char};
 
 #[derive(Clone, Debug)]
@@ -31,8 +32,7 @@ pub struct StringReader<'a> {
     /// Initial position, read-only.
     start_pos: BytePos,
     /// The absolute offset within the source_map of the current character.
-    // FIXME(#64197): `pub` is needed by tests for now.
-    pub pos: BytePos,
+    pos: BytePos,
     /// Stop reading src at this index.
     end_src_index: usize,
     /// Source text to tokenize.
@@ -326,38 +326,27 @@ impl<'a> StringReader<'a> {
         suffix_start: BytePos,
         kind: rustc_lexer::LiteralKind,
     ) -> (token::LitKind, Symbol) {
-        match kind {
+        // prefix means `"` or `br"` or `r###"`, ...
+        let (lit_kind, mode, prefix_len, postfix_len) = match kind {
             rustc_lexer::LiteralKind::Char { terminated } => {
                 if !terminated {
                     self.fatal_span_(start, suffix_start, "unterminated character literal").raise()
                 }
-                let content_start = start + BytePos(1);
-                let content_end = suffix_start - BytePos(1);
-                self.validate_char_escape(content_start, content_end);
-                let id = self.symbol_from_to(content_start, content_end);
-                (token::Char, id)
+                (token::Char, Mode::Char, 1, 1) // ' '
             }
             rustc_lexer::LiteralKind::Byte { terminated } => {
                 if !terminated {
                     self.fatal_span_(start + BytePos(1), suffix_start, "unterminated byte constant")
                         .raise()
                 }
-                let content_start = start + BytePos(2);
-                let content_end = suffix_start - BytePos(1);
-                self.validate_byte_escape(content_start, content_end);
-                let id = self.symbol_from_to(content_start, content_end);
-                (token::Byte, id)
+                (token::Byte, Mode::Byte, 2, 1) // b' '
             }
             rustc_lexer::LiteralKind::Str { terminated } => {
                 if !terminated {
                     self.fatal_span_(start, suffix_start, "unterminated double quote string")
                         .raise()
                 }
-                let content_start = start + BytePos(1);
-                let content_end = suffix_start - BytePos(1);
-                self.validate_str_escape(content_start, content_end);
-                let id = self.symbol_from_to(content_start, content_end);
-                (token::Str, id)
+                (token::Str, Mode::Str, 1, 1) // " "
             }
             rustc_lexer::LiteralKind::ByteStr { terminated } => {
                 if !terminated {
@@ -368,42 +357,28 @@ impl<'a> StringReader<'a> {
                     )
                     .raise()
                 }
-                let content_start = start + BytePos(2);
-                let content_end = suffix_start - BytePos(1);
-                self.validate_byte_str_escape(content_start, content_end);
-                let id = self.symbol_from_to(content_start, content_end);
-                (token::ByteStr, id)
+                (token::ByteStr, Mode::ByteStr, 2, 1) // b" "
             }
             rustc_lexer::LiteralKind::RawStr(unvalidated_raw_str) => {
                 let valid_raw_str = self.validate_and_report_errors(start, unvalidated_raw_str);
                 let n_hashes = valid_raw_str.num_hashes();
                 let n = u32::from(n_hashes);
-
-                let content_start = start + BytePos(2 + n);
-                let content_end = suffix_start - BytePos(1 + n);
-                self.validate_raw_str_escape(content_start, content_end);
-                let id = self.symbol_from_to(content_start, content_end);
-                (token::StrRaw(n_hashes), id)
+                (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
             }
             rustc_lexer::LiteralKind::RawByteStr(unvalidated_raw_str) => {
                 let validated_raw_str = self.validate_and_report_errors(start, unvalidated_raw_str);
                 let n_hashes = validated_raw_str.num_hashes();
                 let n = u32::from(n_hashes);
-
-                let content_start = start + BytePos(3 + n);
-                let content_end = suffix_start - BytePos(1 + n);
-                self.validate_raw_byte_str_escape(content_start, content_end);
-                let id = self.symbol_from_to(content_start, content_end);
-                (token::ByteStrRaw(n_hashes), id)
+                (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
             }
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
-                if empty_int {
+                return if empty_int {
                     self.err_span_(start, suffix_start, "no valid digits found for number");
                     (token::Integer, sym::integer(0))
                 } else {
                     self.validate_int_literal(base, start, suffix_start);
                     (token::Integer, self.symbol_from_to(start, suffix_start))
-                }
+                };
             }
             rustc_lexer::LiteralKind::Float { base, empty_exponent } => {
                 if empty_exponent {
@@ -431,9 +406,18 @@ impl<'a> StringReader<'a> {
                 }
 
                 let id = self.symbol_from_to(start, suffix_start);
-                (token::Float, id)
+                return (token::Float, id);
             }
-        }
+        };
+        let content_start = start + BytePos(prefix_len);
+        let content_end = suffix_start - BytePos(postfix_len);
+        let id = self.symbol_from_to(content_start, content_end);
+        self.validate_literal_escape(mode, content_start, content_end);
+        return (lit_kind, id);
+    }
+
+    pub fn pos(&self) -> BytePos {
+        self.pos
     }
 
     #[inline]
@@ -555,96 +539,23 @@ impl<'a> StringReader<'a> {
         .raise();
     }
 
-    fn validate_char_escape(&self, content_start: BytePos, content_end: BytePos) {
-        let lit = self.str_from_to(content_start, content_end);
-        if let Err((off, err)) = unescape::unescape_char(lit) {
-            emit_unescape_error(
-                &self.sess.span_diagnostic,
-                lit,
-                self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
-                unescape::Mode::Char,
-                0..off,
-                err,
-            )
-        }
-    }
-
-    fn validate_byte_escape(&self, content_start: BytePos, content_end: BytePos) {
-        let lit = self.str_from_to(content_start, content_end);
-        if let Err((off, err)) = unescape::unescape_byte(lit) {
-            emit_unescape_error(
-                &self.sess.span_diagnostic,
-                lit,
-                self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
-                unescape::Mode::Byte,
-                0..off,
-                err,
-            )
-        }
-    }
-
-    fn validate_str_escape(&self, content_start: BytePos, content_end: BytePos) {
-        let lit = self.str_from_to(content_start, content_end);
-        unescape::unescape_str(lit, &mut |range, c| {
-            if let Err(err) = c {
+    fn validate_literal_escape(&self, mode: Mode, content_start: BytePos, content_end: BytePos) {
+        let lit_content = self.str_from_to(content_start, content_end);
+        unescape::unescape_literal(lit_content, mode, &mut |range, result| {
+            // Here we only check for errors. The actual unescaping is done later.
+            if let Err(err) = result {
+                let span_with_quotes =
+                    self.mk_sp(content_start - BytePos(1), content_end + BytePos(1));
                 emit_unescape_error(
                     &self.sess.span_diagnostic,
-                    lit,
-                    self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
-                    unescape::Mode::Str,
+                    lit_content,
+                    span_with_quotes,
+                    mode,
                     range,
                     err,
-                )
-            }
-        })
-    }
-
-    fn validate_raw_str_escape(&self, content_start: BytePos, content_end: BytePos) {
-        let lit = self.str_from_to(content_start, content_end);
-        unescape::unescape_raw_str(lit, &mut |range, c| {
-            if let Err(err) = c {
-                emit_unescape_error(
-                    &self.sess.span_diagnostic,
-                    lit,
-                    self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
-                    unescape::Mode::Str,
-                    range,
-                    err,
-                )
-            }
-        })
-    }
-
-    fn validate_raw_byte_str_escape(&self, content_start: BytePos, content_end: BytePos) {
-        let lit = self.str_from_to(content_start, content_end);
-        unescape::unescape_raw_byte_str(lit, &mut |range, c| {
-            if let Err(err) = c {
-                emit_unescape_error(
-                    &self.sess.span_diagnostic,
-                    lit,
-                    self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
-                    unescape::Mode::ByteStr,
-                    range,
-                    err,
-                )
-            }
-        })
-    }
-
-    fn validate_byte_str_escape(&self, content_start: BytePos, content_end: BytePos) {
-        let lit = self.str_from_to(content_start, content_end);
-        unescape::unescape_byte_str(lit, &mut |range, c| {
-            if let Err(err) = c {
-                emit_unescape_error(
-                    &self.sess.span_diagnostic,
-                    lit,
-                    self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)),
-                    unescape::Mode::ByteStr,
-                    range,
-                    err,
-                )
+                );
             }
-        })
+        });
     }
 
     fn validate_int_literal(&self, base: Base, content_start: BytePos, content_end: BytePos) {
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 437d0ffa119..93c7faf22a7 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -927,7 +927,7 @@ impl<'a> Parser<'a> {
             return Ok(());
         }
         let sm = self.sess.source_map();
-        let msg = format!("expected `;`, found `{}`", super::token_descr(&self.token));
+        let msg = format!("expected `;`, found {}", super::token_descr(&self.token));
         let appl = Applicability::MachineApplicable;
         if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
             // Likely inside a macro, can't provide meaningful suggestions.
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index 75ac8e731b5..6e7d116ce1d 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -931,7 +931,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         if blk.targeted_by_break {
             self.break_ln.insert(blk.hir_id, succ);
         }
-        let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
+        let succ = self.propagate_through_opt_expr(blk.expr.as_deref(), succ);
         blk.stmts.iter().rev().fold(succ, |succ, stmt| self.propagate_through_stmt(stmt, succ))
     }
 
@@ -952,7 +952,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 // initialization, which is mildly more complex than checking
                 // once at the func header but otherwise equivalent.
 
-                let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
+                let succ = self.propagate_through_opt_expr(local.init.as_deref(), succ);
                 self.define_bindings_in_pat(&local.pat, succ)
             }
             hir::StmtKind::Item(..) => succ,
diff --git a/src/librustc_passes/region.rs b/src/librustc_passes/region.rs
index 927e6a7e712..a6fa677cbc0 100644
--- a/src/librustc_passes/region.rs
+++ b/src/librustc_passes/region.rs
@@ -797,7 +797,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
         resolve_expr(self, ex);
     }
     fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
-        resolve_local(self, Some(&l.pat), l.init.as_ref().map(|e| &**e));
+        resolve_local(self, Some(&l.pat), l.init.as_deref());
     }
 }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 917e2f54830..b474b23ac4f 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -160,7 +160,7 @@ where
                     }
                 }
             }
-            ty::Projection(proj) | ty::UnnormalizedProjection(proj) => {
+            ty::Projection(proj) => {
                 if self.def_id_visitor.skip_assoc_tys() {
                     // Visitors searching for minimal visibility/reachability want to
                     // conservatively approximate associated types like `<Type as Trait>::Alias`
diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs
index 36343365ab6..d8875f8ac64 100644
--- a/src/librustc_query_system/dep_graph/dep_node.rs
+++ b/src/librustc_query_system/dep_graph/dep_node.rs
@@ -80,7 +80,7 @@ impl<K: DepKind> DepNode<K> {
             }
         }
 
-        return dep_node;
+        dep_node
     }
 }
 
diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs
index 5f14a09b24d..04a45090b72 100644
--- a/src/librustc_query_system/dep_graph/graph.rs
+++ b/src/librustc_query_system/dep_graph/graph.rs
@@ -860,8 +860,8 @@ impl<K: DepKind> DepGraph<K> {
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct WorkProduct {
     pub cgu_name: String,
-    /// Saved files associated with this CGU.
-    pub saved_files: Vec<String>,
+    /// Saved file associated with this CGU.
+    pub saved_file: Option<String>,
 }
 
 #[derive(Clone)]
diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs
index f85462eb78b..e8d02692f37 100644
--- a/src/librustc_query_system/dep_graph/mod.rs
+++ b/src/librustc_query_system/dep_graph/mod.rs
@@ -77,9 +77,9 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash {
         OP: FnOnce() -> R;
 
     /// Access dependencies from current implicit context.
-    fn read_deps<OP>(op: OP) -> ()
+    fn read_deps<OP>(op: OP)
     where
-        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>) -> ();
+        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
 
     fn can_reconstruct_query_key(&self) -> bool;
 }
diff --git a/src/librustc_query_system/lib.rs b/src/librustc_query_system/lib.rs
index 0e6a07e06d0..8e350d3ba26 100644
--- a/src/librustc_query_system/lib.rs
+++ b/src/librustc_query_system/lib.rs
@@ -4,7 +4,7 @@
 #![feature(const_panic)]
 #![feature(core_intrinsics)]
 #![feature(hash_raw_entry)]
-#![feature(specialization)]
+#![feature(specialization)] // FIXME: min_specialization rejects `default const`
 #![feature(stmt_expr_attributes)]
 #![feature(vec_remove_item)]
 
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 534fe172bef..3dd715f9e3d 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -21,7 +21,7 @@ use rustc_ast::walk_list;
 use rustc_ast_pretty::pprust::{bounds_to_string, generic_params_to_string, ty_to_string};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind as HirDefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::config::Input;
@@ -104,12 +104,10 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         self.dumper.analysis()
     }
 
-    fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
+    fn nest_tables<F>(&mut self, item_def_id: LocalDefId, f: F)
     where
         F: FnOnce(&mut Self),
     {
-        let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id);
-
         let tables = if self.tcx.has_typeck_tables(item_def_id) {
             self.tcx.typeck_tables_of(item_def_id)
         } else {
@@ -272,8 +270,9 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
     ) {
         debug!("process_method: {}:{}", id, ident);
 
-        let hir_id = self.tcx.hir().node_id_to_hir_id(id);
-        self.nest_tables(id, |v| {
+        let map = &self.tcx.hir();
+        let hir_id = map.node_id_to_hir_id(id);
+        self.nest_tables(map.local_def_id(hir_id), |v| {
             if let Some(mut method_data) = v.save_ctxt.get_method_data(id, ident, span) {
                 v.process_formals(&sig.decl.inputs, &method_data.qualname);
                 v.process_generic_params(&generics, &method_data.qualname, id);
@@ -296,7 +295,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 // start walking from the newly-created definition.
                 match sig.header.asyncness {
                     ast::Async::Yes { return_impl_trait_id, .. } => {
-                        v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty))
+                        let hir_id = map.node_id_to_hir_id(return_impl_trait_id);
+                        v.nest_tables(map.local_def_id(hir_id), |v| v.visit_ty(ret_ty))
                     }
                     _ => v.visit_ty(ret_ty),
                 }
@@ -364,8 +364,9 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         ty_params: &'l ast::Generics,
         body: Option<&'l ast::Block>,
     ) {
-        let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
-        self.nest_tables(item.id, |v| {
+        let map = &self.tcx.hir();
+        let hir_id = map.node_id_to_hir_id(item.id);
+        self.nest_tables(map.local_def_id(hir_id), |v| {
             if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(fn_data, DefData, item.span);
                 v.process_formals(&decl.inputs, &fn_data.qualname);
@@ -389,7 +390,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     // start walking from the newly-created definition.
                     match header.asyncness {
                         ast::Async::Yes { return_impl_trait_id, .. } => {
-                            v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty))
+                            let hir_id = map.node_id_to_hir_id(return_impl_trait_id);
+                            v.nest_tables(map.local_def_id(hir_id), |v| v.visit_ty(ret_ty))
                         }
                         _ => v.visit_ty(ret_ty),
                     }
@@ -407,7 +409,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         expr: Option<&'l ast::Expr>,
     ) {
         let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
-        self.nest_tables(item.id, |v| {
+        self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(var_data, DefData, item.span);
                 v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), var_data);
@@ -427,15 +429,13 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         vis: ast::Visibility,
         attrs: &'l [Attribute],
     ) {
-        let qualname = format!(
-            "::{}",
-            self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(id).to_def_id())
-        );
+        let hir_id = self.tcx.hir().node_id_to_hir_id(id);
+        let qualname =
+            format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(hir_id).to_def_id()));
 
         if !self.span.filter_generated(ident.span) {
             let sig = sig::assoc_const_signature(id, ident.name, typ, expr, &self.save_ctxt);
             let span = self.span_from_span(ident.span);
-            let hir_id = self.tcx.hir().node_id_to_hir_id(id);
 
             self.dumper.dump_def(
                 &access_from_vis!(self.save_ctxt, vis, hir_id),
@@ -457,7 +457,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         }
 
         // walk type and init value
-        self.nest_tables(id, |v| {
+        self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
             v.visit_ty(typ);
             if let Some(expr) = expr {
                 v.visit_expr(expr);
@@ -474,10 +474,9 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
     ) {
         debug!("process_struct {:?} {:?}", item, item.span);
         let name = item.ident.to_string();
-        let qualname = format!(
-            "::{}",
-            self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id())
-        );
+        let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
+        let qualname =
+            format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(hir_id).to_def_id()));
 
         let kind = match item.kind {
             ast::ItemKind::Struct(_, _) => DefKind::Struct,
@@ -509,7 +508,6 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
         if !self.span.filter_generated(item.ident.span) {
             let span = self.span_from_span(item.ident.span);
-            let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
             self.dumper.dump_def(
                 &access_from!(self.save_ctxt, item, hir_id),
                 Def {
@@ -529,7 +527,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
             );
         }
 
-        self.nest_tables(item.id, |v| {
+        self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
             for field in def.fields() {
                 v.process_struct_field_def(field, item.id);
                 v.visit_ty(&field.ty);
@@ -669,14 +667,15 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         }
 
         let map = &self.tcx.hir();
-        self.nest_tables(item.id, |v| {
+        let hir_id = map.node_id_to_hir_id(item.id);
+        self.nest_tables(map.local_def_id(hir_id), |v| {
             v.visit_ty(&typ);
             if let &Some(ref trait_ref) = trait_ref {
                 v.process_path(trait_ref.ref_id, &trait_ref.path);
             }
             v.process_generic_params(generics, "", item.id);
             for impl_item in impl_items {
-                v.process_impl_item(impl_item, map.local_def_id_from_node_id(item.id).to_def_id());
+                v.process_impl_item(impl_item, map.local_def_id(hir_id).to_def_id());
             }
         });
     }
@@ -1411,7 +1410,10 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
             }
             ast::TyKind::Array(ref element, ref length) => {
                 self.visit_ty(element);
-                self.nest_tables(length.id, |v| v.visit_expr(&length.value));
+                let hir_id = self.tcx.hir().node_id_to_hir_id(length.id);
+                self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
+                    v.visit_expr(&length.value)
+                });
             }
             ast::TyKind::ImplTrait(id, ref bounds) => {
                 // FIXME: As of writing, the opaque type lowering introduces
@@ -1423,7 +1425,13 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                 // bounds...
                 // This will panic if called on return type `impl Trait`, which
                 // we guard against in `process_fn`.
-                self.nest_tables(id, |v| v.process_bounds(bounds));
+                // FIXME(#71104) Should really be using just `node_id_to_hir_id` but
+                // some `NodeId` do not seem to have a corresponding HirId.
+                if let Some(hir_id) = self.tcx.hir().opt_node_id_to_hir_id(id) {
+                    self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
+                        v.process_bounds(bounds)
+                    });
+                }
             }
             _ => visit::walk_ty(self, t),
         }
@@ -1471,7 +1479,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                 }
 
                 // walk the body
-                self.nest_tables(ex.id, |v| {
+                let hir_id = self.tcx.hir().node_id_to_hir_id(ex.id);
+                self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
                     v.process_formals(&decl.inputs, &id);
                     v.visit_expr(body)
                 });
@@ -1488,7 +1497,10 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
             }
             ast::ExprKind::Repeat(ref element, ref count) => {
                 self.visit_expr(element);
-                self.nest_tables(count.id, |v| v.visit_expr(&count.value));
+                let hir_id = self.tcx.hir().node_id_to_hir_id(count.id);
+                self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
+                    v.visit_expr(&count.value)
+                });
             }
             // In particular, we take this branch for call and path expressions,
             // where we'll index the idents involved just by continuing to walk.
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index be1c358d58e..e2c82a397c7 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -271,6 +271,7 @@ macro_rules! options {
             "one of supported relocation models (`rustc --print relocation-models`)";
         pub const parse_tls_model: &str =
             "one of supported TLS models (`rustc --print tls-models`)";
+        pub const parse_target_feature: &str = parse_string;
     }
 
     #[allow(dead_code)]
@@ -647,6 +648,19 @@ macro_rules! options {
             }
             true
         }
+
+        fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => {
+                    if !slot.is_empty() {
+                        slot.push_str(",");
+                    }
+                    slot.push_str(s);
+                    true
+                }
+                None => false,
+            }
+        }
     }
 ) }
 
@@ -742,7 +756,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "use soft float ABI (*eabihf targets only) (default: no)"),
     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select target processor (`rustc --print target-cpus` for details)"),
-    target_feature: String = (String::new(), parse_string, [TRACKED],
+    target_feature: String = (String::new(), parse_target_feature, [TRACKED],
         "target specific attributes. (`rustc --print target-features` for details). \
         This feature is unsafe."),
 
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs
index 4b1cc71c822..cb5bd37442a 100644
--- a/src/librustc_session/session.rs
+++ b/src/librustc_session/session.rs
@@ -808,7 +808,7 @@ impl Session {
                 let mut fuel = self.optimization_fuel.lock();
                 ret = fuel.remaining != 0;
                 if fuel.remaining == 0 && !fuel.out_of_fuel {
-                    eprintln!("optimization-fuel-exhausted: {}", msg());
+                    self.warn(&format!("optimization-fuel-exhausted: {}", msg()));
                     fuel.out_of_fuel = true;
                 } else if fuel.remaining > 0 {
                     fuel.remaining -= 1;
@@ -936,6 +936,16 @@ impl Session {
         // then try to skip it where possible.
         dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
     }
+
+    /// Checks if LLVM lifetime markers should be emitted.
+    pub fn emit_lifetime_markers(&self) -> bool {
+        match self.opts.debugging_opts.sanitizer {
+            // AddressSanitizer uses lifetimes to detect use after scope bugs.
+            // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
+            Some(Sanitizer::Address | Sanitizer::Memory) => true,
+            _ => self.opts.optimize != config::OptLevel::No,
+        }
+    }
 }
 
 pub fn build_session(
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index dd7ba5cb6fc..58cdb87158a 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -12,7 +12,7 @@
 #![feature(negative_impls)]
 #![feature(nll)]
 #![feature(optin_builtin_traits)]
-#![feature(specialization)]
+#![feature(min_specialization)]
 
 // FIXME(#56935): Work around ICEs during cross-compilation.
 #[allow(unused)]
diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs
index d27aae0d6ed..51f55417663 100644
--- a/src/librustc_span/source_map.rs
+++ b/src/librustc_span/source_map.rs
@@ -910,14 +910,23 @@ impl SourceMap {
 
     pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
         let prev_span = self.span_extend_to_prev_str(span, "fn", true);
-        self.span_to_snippet(prev_span)
-            .map(|snippet| {
-                let len = snippet
-                    .find(|c: char| !c.is_alphanumeric() && c != '_')
-                    .expect("no label after fn");
-                prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))
-            })
-            .ok()
+        if let Ok(snippet) = self.span_to_snippet(prev_span) {
+            debug!(
+                "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
+                span, prev_span, snippet
+            );
+
+            if snippet.is_empty() {
+                return None;
+            };
+
+            let len = snippet
+                .find(|c: char| !c.is_alphanumeric() && c != '_')
+                .expect("no label after fn");
+            Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32)))
+        } else {
+            None
+        }
     }
 
     /// Takes the span of a type parameter in a function signature and try to generate a span for
diff --git a/src/librustc_symbol_mangling/legacy.rs b/src/librustc_symbol_mangling/legacy.rs
index 01e9356b42f..3038b0c6bd7 100644
--- a/src/librustc_symbol_mangling/legacy.rs
+++ b/src/librustc_symbol_mangling/legacy.rs
@@ -216,7 +216,6 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> {
             ty::FnDef(def_id, substs)
             | ty::Opaque(def_id, substs)
             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
-            | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs })
             | ty::Closure(def_id, substs)
             | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
             _ => self.pretty_print_type(ty),
@@ -264,7 +263,6 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> {
             ty::FnDef(..)
             | ty::Opaque(..)
             | ty::Projection(_)
-            | ty::UnnormalizedProjection(_)
             | ty::Closure(..)
             | ty::Generator(..)
                 if trait_ref.is_none() =>
diff --git a/src/librustc_symbol_mangling/v0.rs b/src/librustc_symbol_mangling/v0.rs
index 53df140e0b5..3b439e09a9d 100644
--- a/src/librustc_symbol_mangling/v0.rs
+++ b/src/librustc_symbol_mangling/v0.rs
@@ -413,7 +413,6 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
             | ty::FnDef(def_id, substs)
             | ty::Opaque(def_id, substs)
             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
-            | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs })
             | ty::Closure(def_id, substs)
             | ty::Generator(def_id, substs, _) => {
                 self = self.print_def_path(def_id, substs)?;
diff --git a/src/librustc_target/spec/mipsel_sony_psp.rs b/src/librustc_target/spec/mipsel_sony_psp.rs
new file mode 100644
index 00000000000..0c74454d0c5
--- /dev/null
+++ b/src/librustc_target/spec/mipsel_sony_psp.rs
@@ -0,0 +1,43 @@
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, RelocModel};
+use crate::spec::{Target, TargetOptions, TargetResult};
+
+// The PSP has custom linker requirements.
+const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld");
+
+pub fn target() -> TargetResult {
+    let mut pre_link_args = LinkArgs::new();
+    pre_link_args.insert(
+        LinkerFlavor::Lld(LldFlavor::Ld),
+        vec!["--eh-frame-hdr".to_string(), "--emit-relocs".to_string()],
+    );
+
+    Ok(Target {
+        llvm_target: "mipsel-sony-psp".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
+        arch: "mips".to_string(),
+        target_os: "psp".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "sony".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+
+        options: TargetOptions {
+            cpu: "mips2".to_string(),
+            executables: true,
+            linker: Some("rust-lld".to_owned()),
+            linker_is_gnu: true,
+            relocation_model: RelocModel::Static,
+
+            // PSP FPU only supports single precision floats.
+            features: "+single-float".to_string(),
+
+            // PSP does not support trap-on-condition instructions.
+            llvm_args: vec!["-mno-check-zero-division".to_string()],
+            pre_link_args,
+            link_script: Some(LINKER_SCRIPT.to_string()),
+            ..Default::default()
+        },
+    })
+}
diff --git a/src/librustc_target/spec/mipsel_sony_psp_linker_script.ld b/src/librustc_target/spec/mipsel_sony_psp_linker_script.ld
new file mode 100644
index 00000000000..1bd436d6f94
--- /dev/null
+++ b/src/librustc_target/spec/mipsel_sony_psp_linker_script.ld
@@ -0,0 +1,34 @@
+ENTRY(module_start)
+SECTIONS
+{
+  /* PRX format requires text to begin at 0 */
+  .text 0 : { *(.text .text.*) }
+
+  /* Sort stubs for convenient ordering */
+  .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) }
+
+  /* Keep these sections around, even though they may appear unused to the linker */
+  .lib.ent.top :  { KEEP(*(.lib.ent.top)) }
+  .lib.ent :      { KEEP(*(.lib.ent)) }
+  .lib.ent.btm :  { KEEP(*(.lib.ent.btm)) }
+  .lib.stub.top : { KEEP(*(.lib.stub.top)) }
+  .lib.stub :     { KEEP(*(.lib.stub)) }
+  .lib.stub.btm : { KEEP(*(.lib.stub.btm)) }
+  .eh_frame_hdr : { KEEP(*(.eh_frame_hdr)) }
+
+  /* Add symbols for LLVM's libunwind */
+  __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
+  __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
+  .eh_frame :
+  {
+    __eh_frame_start = .;
+    KEEP(*(.eh_frame))
+    __eh_frame_end = .;
+  }
+
+  /* These are explicitly listed to avoid being merged into .rodata */
+  .rodata.sceResident : { *(.rodata.sceResident) }
+  .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) }
+  /* Sort NIDs for convenient ordering */
+  .rodata.sceNid : { *(.rodata.sceNid) *(SORT(.rodata.sceNid.*)) }
+}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 477161dc658..c7b2023ddca 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -582,6 +582,8 @@ supported_targets! {
     ("powerpc-wrs-vxworks", powerpc_wrs_vxworks),
     ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
     ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
+
+    ("mipsel-sony-psp", mipsel_sony_psp),
 }
 
 /// Everything `rustc` knows about how to compile for a specific target.
@@ -666,6 +668,10 @@ pub struct TargetOptions {
     /// Linker arguments that are unconditionally passed *after* any
     /// user-defined libraries.
     pub post_link_args: LinkArgs,
+    /// Optional link script applied to `dylib` and `executable` crate types.
+    /// This is a string containing the script, not a path. Can only be applied
+    /// to linkers where `linker_is_gnu` is true.
+    pub link_script: Option<String>,
 
     /// Environment variables to be set for the linker invocation.
     pub link_env: Vec<(String, String)>,
@@ -899,6 +905,7 @@ impl Default for TargetOptions {
             pre_link_args: LinkArgs::new(),
             pre_link_args_crt: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
+            link_script: None,
             asm_args: Vec::new(),
             cpu: "generic".to_string(),
             features: String::new(),
@@ -1249,6 +1256,7 @@ impl Target {
         key!(post_link_objects, list);
         key!(post_link_objects_crt, list);
         key!(post_link_args, link_args);
+        key!(link_script, optional);
         key!(link_env, env);
         key!(link_env_remove, list);
         key!(asm_args, list);
@@ -1479,6 +1487,7 @@ impl ToJson for Target {
         target_option_val!(post_link_objects);
         target_option_val!(post_link_objects_crt);
         target_option_val!(link_args - post_link_args);
+        target_option_val!(link_script);
         target_option_val!(env - link_env);
         target_option_val!(link_env_remove);
         target_option_val!(asm_args);
diff --git a/src/librustc_trait_selection/traits/chalk_fulfill.rs b/src/librustc_trait_selection/traits/chalk_fulfill.rs
index 115e4a0e629..be0512dcac9 100644
--- a/src/librustc_trait_selection/traits/chalk_fulfill.rs
+++ b/src/librustc_trait_selection/traits/chalk_fulfill.rs
@@ -39,7 +39,7 @@ fn environment<'tcx>(
     let ty::InstantiatedPredicates { predicates, .. } =
         tcx.predicates_of(def_id).instantiate_identity(tcx);
 
-    let clauses = predicates.into_iter().map(|pred| ChalkEnvironmentClause::Predicate(pred));
+    let clauses = predicates.into_iter().map(ChalkEnvironmentClause::Predicate);
 
     let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
     let node = tcx.hir().get(hir_id);
@@ -224,7 +224,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
                                 ),
 
                                 Err(_err) => errors.push(FulfillmentError {
-                                    obligation: obligation,
+                                    obligation,
                                     code: FulfillmentErrorCode::CodeSelectionError(
                                         SelectionError::Unimplemented,
                                     ),
@@ -238,7 +238,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
                     }
 
                     Err(NoSolution) => errors.push(FulfillmentError {
-                        obligation: obligation,
+                        obligation,
                         code: FulfillmentErrorCode::CodeSelectionError(
                             SelectionError::Unimplemented,
                         ),
@@ -257,6 +257,6 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
     }
 
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
-        self.obligations.iter().map(|obligation| obligation.clone()).collect()
+        self.obligations.iter().cloned().collect()
     }
 }
diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs
index f9ff772900b..85c2f9246af 100644
--- a/src/librustc_trait_selection/traits/coherence.rs
+++ b/src/librustc_trait_selection/traits/coherence.rs
@@ -567,9 +567,8 @@ fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>>
 
         ty::Error => None,
 
-        ty::UnnormalizedProjection(..)
-        | ty::Closure(..)
-        | ty::Generator(..)
-        | ty::GeneratorWitness(..) => bug!("ty_is_local invoked on unexpected type: {:?}", ty),
+        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+            bug!("ty_is_local invoked on unexpected type: {:?}", ty)
+        }
     }
 }
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 405c656bad5..0d53df3bf4b 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -283,6 +283,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             .unwrap_or(false);
                         let is_from = format!("{}", trait_ref.print_only_trait_path())
                             .starts_with("std::convert::From<");
+                        let is_unsize =
+                            { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
                         let (message, note) = if is_try && is_from {
                             (
                                 Some(format!(
@@ -400,11 +402,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
                         self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
                         self.note_version_mismatch(&mut err, &trait_ref);
+                        self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span);
                         if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
                             err.emit();
                             return;
                         }
 
+                        if is_unsize {
+                            // If the obligation failed due to a missing implementation of the
+                            // `Unsize` trait, give a pointer to why that might be the case
+                            err.note(
+                                "all implementations of `Unsize` are provided \
+                                automatically by the compiler, see \
+                                <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \
+                                for more information",
+                            );
+                        }
+
                         // Try to report a help message
                         if !trait_ref.has_infer_types_or_consts()
                             && self.predicate_can_apply(obligation.param_env, trait_ref)
@@ -427,12 +441,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                 let impl_candidates = self.find_similar_impl_candidates(trait_ref);
                                 self.report_similar_impl_candidates(impl_candidates, &mut err);
                             }
-                            self.suggest_change_mut(
-                                &obligation,
-                                &mut err,
-                                &trait_ref,
-                                points_at_arg,
-                            );
+                            // Changing mutability doesn't make a difference to whether we have
+                            // an `Unsize` impl (Fixes ICE in #71036)
+                            if !is_unsize {
+                                self.suggest_change_mut(
+                                    &obligation,
+                                    &mut err,
+                                    &trait_ref,
+                                    points_at_arg,
+                                );
+                            }
                         }
 
                         // If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -1194,7 +1212,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 ty::Foreign(..) => Some(19),
                 ty::GeneratorWitness(..) => Some(20),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None,
-                ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
             }
         }
 
@@ -1638,7 +1655,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                     {
                         let (span, separator) = match param.bounds {
                             [] => (span.shrink_to_hi(), ":"),
-                            [.., bound] => (bound.span().shrink_to_hi(), " + "),
+                            [.., bound] => (bound.span().shrink_to_hi(), " +"),
                         };
                         err.span_suggestion_verbose(
                             span,
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 74dd47a91c2..c098e44fa06 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1,21 +1,24 @@
 use super::{
     EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+    SelectionContext,
 };
 
 use crate::infer::InferCtxt;
+use crate::traits::normalize_projection_type;
 
 use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::TypeckTables;
 use rustc_middle::ty::{
     self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
     TyCtxt, TypeFoldable, WithConstness,
 };
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
@@ -150,13 +153,22 @@ pub trait InferCtxtExt<'tcx> {
         T: fmt::Display;
 
     fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
+
+    /// Suggest to await before try: future? => future.await?
+    fn suggest_await_before_try(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        span: Span,
+    );
 }
 
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
     (
         generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
         format!(
-            "{} {} ",
+            "{} {}",
             if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
             pred,
         ),
@@ -173,7 +185,13 @@ fn suggest_restriction(
     fn_sig: Option<&hir::FnSig<'_>>,
     projection: Option<&ty::ProjectionTy<'_>>,
     trait_ref: ty::PolyTraitRef<'_>,
+    super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
 ) {
+    // When we are dealing with a trait, `super_traits` will be `Some`:
+    // Given `trait T: A + B + C {}`
+    //              -  ^^^^^^^^^ GenericBounds
+    //              |
+    //              &Ident
     let span = generics.where_clause.span_for_predicates_or_empty_place();
     if span.from_expansion() || span.desugaring_kind().is_some() {
         return;
@@ -262,10 +280,28 @@ fn suggest_restriction(
         );
     } else {
         // Trivial case: `T` needs an extra bound: `T: Bound`.
-        let (sp, sugg) =
-            predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string());
-        let appl = Applicability::MachineApplicable;
-        err.span_suggestion(sp, &format!("consider further restricting {}", msg), sugg, appl);
+        let (sp, suggestion) = match super_traits {
+            None => {
+                predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string())
+            }
+            Some((ident, bounds)) => match bounds {
+                [.., bound] => (
+                    bound.span().shrink_to_hi(),
+                    format!(" + {}", trait_ref.print_only_trait_path().to_string()),
+                ),
+                [] => (
+                    ident.span.shrink_to_hi(),
+                    format!(": {}", trait_ref.print_only_trait_path().to_string()),
+                ),
+            },
+        };
+
+        err.span_suggestion_verbose(
+            sp,
+            &format!("consider further restricting {}", msg),
+            suggestion,
+            Applicability::MachineApplicable,
+        );
     }
 }
 
@@ -288,13 +324,35 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let mut hir_id = body_id;
         while let Some(node) = self.tcx.hir().find(hir_id) {
             match node {
+                hir::Node::Item(hir::Item {
+                    ident,
+                    kind: hir::ItemKind::Trait(_, _, generics, bounds, _),
+                    ..
+                }) if self_ty == self.tcx.types.self_param => {
+                    assert!(param_ty);
+                    // Restricting `Self` for a single method.
+                    suggest_restriction(
+                        &generics,
+                        "`Self`",
+                        err,
+                        None,
+                        projection,
+                        trait_ref,
+                        Some((ident, bounds)),
+                    );
+                    return;
+                }
+
                 hir::Node::TraitItem(hir::TraitItem {
                     generics,
                     kind: hir::TraitItemKind::Fn(..),
                     ..
-                }) if param_ty && self_ty == self.tcx.types.self_param => {
+                }) if self_ty == self.tcx.types.self_param => {
+                    assert!(param_ty);
                     // Restricting `Self` for a single method.
-                    suggest_restriction(&generics, "`Self`", err, None, projection, trait_ref);
+                    suggest_restriction(
+                        &generics, "`Self`", err, None, projection, trait_ref, None,
+                    );
                     return;
                 }
 
@@ -319,6 +377,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         Some(fn_sig),
                         projection,
                         trait_ref,
+                        None,
                     );
                     return;
                 }
@@ -336,6 +395,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         None,
                         projection,
                         trait_ref,
+                        None,
                     );
                     return;
                 }
@@ -691,6 +751,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             }
 
             if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind {
+                if region.is_late_bound() || t_type.has_escaping_bound_vars() {
+                    // Avoid debug assertion in `mk_obligation_for_def_id`.
+                    //
+                    // If the self type has escaping bound vars then it's not
+                    // going to be the type of an expression, so the suggestion
+                    // probably won't apply anyway.
+                    return;
+                }
+
                 let trait_type = match mutability {
                     hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
                     hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
@@ -1616,7 +1685,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if suggest_const_in_array_repeat_expressions {
                     err.note(
                         "this array initializer can be evaluated at compile-time, see issue \
-                         #48147 <https://github.com/rust-lang/rust/issues/49147> \
+                         #49147 <https://github.com/rust-lang/rust/issues/49147> \
                          for more information",
                     );
                     if tcx.sess.opts.unstable_features.is_nightly_build() {
@@ -1765,6 +1834,95 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             suggested_limit, self.tcx.crate_name,
         ));
     }
+
+    fn suggest_await_before_try(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        span: Span,
+    ) {
+        debug!(
+            "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}",
+            obligation,
+            span,
+            trait_ref,
+            trait_ref.self_ty()
+        );
+        let body_hir_id = obligation.cause.body_id;
+        let item_id = self.tcx.hir().get_parent_node(body_hir_id);
+
+        if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) {
+            let body = self.tcx.hir().body(body_id);
+            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
+                let future_trait =
+                    self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None);
+
+                let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty());
+
+                let impls_future = self.tcx.type_implements_trait((
+                    future_trait,
+                    self_ty,
+                    ty::List::empty(),
+                    obligation.param_env,
+                ));
+
+                let item_def_id = self
+                    .tcx
+                    .associated_items(future_trait)
+                    .in_definition_order()
+                    .next()
+                    .unwrap()
+                    .def_id;
+                // `<T as Future>::Output`
+                let projection_ty = ty::ProjectionTy {
+                    // `T`
+                    substs: self.tcx.mk_substs_trait(
+                        trait_ref.self_ty(),
+                        self.fresh_substs_for_item(span, item_def_id),
+                    ),
+                    // `Future::Output`
+                    item_def_id,
+                };
+
+                let mut selcx = SelectionContext::new(self);
+
+                let mut obligations = vec![];
+                let normalized_ty = normalize_projection_type(
+                    &mut selcx,
+                    obligation.param_env,
+                    projection_ty,
+                    obligation.cause.clone(),
+                    0,
+                    &mut obligations,
+                );
+
+                debug!(
+                    "suggest_await_befor_try: normalized_projection_type {:?}",
+                    self.resolve_vars_if_possible(&normalized_ty)
+                );
+                let try_obligation = self.mk_obligation_for_def_id(
+                    trait_ref.def_id(),
+                    normalized_ty,
+                    obligation.cause.clone(),
+                    obligation.param_env,
+                );
+                debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation);
+                if self.predicate_may_hold(&try_obligation) && impls_future {
+                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                        if snippet.ends_with('?') {
+                            err.span_suggestion(
+                                span,
+                                "consider using `.await` here",
+                                format!("{}.await?", snippet.trim_end_matches('?')),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
 
 /// Collect all the returned expressions within the input expression.
@@ -1854,7 +2012,7 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] {
     fn next_type_param_name(&self, name: Option<&str>) -> String {
         // This is the whitelist of possible parameter names that we might suggest.
         let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase());
-        let name = name.as_ref().map(|s| s.as_str());
+        let name = name.as_deref();
         let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
         let used_names = self
             .iter()
diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs
index 778430fc2ca..9592f93ce2e 100644
--- a/src/librustc_trait_selection/traits/mod.rs
+++ b/src/librustc_trait_selection/traits/mod.rs
@@ -31,7 +31,9 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::middle::region;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{
+    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness,
+};
 use rustc_span::Span;
 
 use std::fmt::Debug;
@@ -523,6 +525,43 @@ fn vtable_methods<'tcx>(
     }))
 }
 
+/// Check whether a `ty` implements given trait(trait_def_id).
+///
+/// NOTE: Always return `false` for a type which needs inference.
+fn type_implements_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (
+        DefId,    // trait_def_id,
+        Ty<'tcx>, // type
+        SubstsRef<'tcx>,
+        ParamEnv<'tcx>,
+    ),
+) -> bool {
+    let (trait_def_id, ty, params, param_env) = key;
+
+    debug!(
+        "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
+        trait_def_id, ty, params, param_env
+    );
+
+    // Do not check on infer_types to avoid panic in evaluate_obligation.
+    if ty.has_infer_types() {
+        return false;
+    }
+
+    let ty = tcx.erase_regions(&ty);
+
+    let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
+
+    let obligation = Obligation {
+        cause: ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: trait_ref.without_const().to_predicate(),
+    };
+    tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+}
+
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     object_safety::provide(providers);
     *providers = ty::query::Providers {
@@ -531,6 +570,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
         vtable_methods,
         substitute_normalize_and_test_predicates,
+        type_implements_trait,
         ..*providers
     };
 }
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 47df82690e0..0779882b6dd 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -20,6 +20,7 @@ use crate::traits::error_reporting::InferCtxtExt;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
@@ -1222,7 +1223,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
 
     let tcx = selcx.tcx();
 
-    let gen_def_id = tcx.lang_items().gen_trait().unwrap();
+    let gen_def_id = tcx.require_lang_item(GeneratorTraitLangItem, None);
 
     let predicate = super::util::generator_trait_ref_and_outputs(
         tcx,
@@ -1309,7 +1310,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
     debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
 
     // the `Output` associated type is declared on `FnOnce`
-    let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap();
+    let fn_once_def_id = tcx.require_lang_item(FnOnceTraitLangItem, None);
 
     let predicate = super::util::closure_trait_ref_and_return_type(
         tcx,
diff --git a/src/librustc_trait_selection/traits/query/dropck_outlives.rs b/src/librustc_trait_selection/traits/query/dropck_outlives.rs
index 64cc5fadeab..856a2111fc8 100644
--- a/src/librustc_trait_selection/traits/query/dropck_outlives.rs
+++ b/src/librustc_trait_selection/traits/query/dropck_outlives.rs
@@ -135,7 +135,5 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Infer(_)
         | ty::Bound(..)
         | ty::Generator(..) => false,
-
-        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
     }
 }
diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs
index b595f77e4d6..f0ff30232b9 100644
--- a/src/librustc_trait_selection/traits/select.rs
+++ b/src/librustc_trait_selection/traits/select.rs
@@ -2178,8 +2178,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
             ty::Infer(ty::TyVar(_)) => Ambiguous,
 
-            ty::UnnormalizedProjection(..)
-            | ty::Placeholder(..)
+            ty::Placeholder(..)
             | ty::Bound(..)
             | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
@@ -2250,8 +2249,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ambiguous
             }
 
-            ty::UnnormalizedProjection(..)
-            | ty::Placeholder(..)
+            ty::Placeholder(..)
             | ty::Bound(..)
             | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
@@ -2284,8 +2282,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Never
             | ty::Char => Vec::new(),
 
-            ty::UnnormalizedProjection(..)
-            | ty::Placeholder(..)
+            ty::Placeholder(..)
             | ty::Dynamic(..)
             | ty::Param(..)
             | ty::Foreign(..)
diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs
index 8007290f35d..eb63505b69b 100644
--- a/src/librustc_trait_selection/traits/structural_match.rs
+++ b/src/librustc_trait_selection/traits/structural_match.rs
@@ -4,6 +4,7 @@ use crate::traits::{self, ConstPatternStructural, TraitEngine};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem};
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::Span;
 
@@ -69,7 +70,7 @@ pub fn type_marked_structural(
     let mut fulfillment_cx = traits::FulfillmentContext::new();
     let cause = ObligationCause::new(span, id, ConstPatternStructural);
     // require `#[derive(PartialEq)]`
-    let structural_peq_def_id = infcx.tcx.lang_items().structural_peq_trait().unwrap();
+    let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span));
     fulfillment_cx.register_bound(
         infcx,
         ty::ParamEnv::empty(),
@@ -80,7 +81,7 @@ pub fn type_marked_structural(
     // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
     // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
     let cause = ObligationCause::new(span, id, ConstPatternStructural);
-    let structural_teq_def_id = infcx.tcx.lang_items().structural_teq_trait().unwrap();
+    let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span));
     fulfillment_cx.register_bound(
         infcx,
         ty::ParamEnv::empty(),
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 1d4afeaae42..ba7ec96775c 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -389,8 +389,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     self.compute_projection(data);
                 }
 
-                ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
                 ty::Adt(def, substs) => {
                     // WfNominalType
                     let obligations = self.nominal_obligations(def.did, substs);
diff --git a/src/librustc_traits/chalk/db.rs b/src/librustc_traits/chalk/db.rs
index 0cec583bb56..a2aee9b6ef7 100644
--- a/src/librustc_traits/chalk/db.rs
+++ b/src/librustc_traits/chalk/db.rs
@@ -59,7 +59,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         // clauses or bounds?
         let predicates = self.tcx.predicates_defined_on(def_id).predicates;
         let where_clauses: Vec<_> = predicates
-            .into_iter()
+            .iter()
             .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
 
@@ -88,7 +88,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         let binders = binders_for(&self.interner, bound_vars);
         let predicates = self.tcx.predicates_defined_on(def_id).predicates;
         let where_clauses: Vec<_> = predicates
-            .into_iter()
+            .iter()
             .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
 
@@ -134,7 +134,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
                 let predicates = self.tcx.predicates_of(adt_def_id).predicates;
                 let where_clauses: Vec<_> = predicates
-                    .into_iter()
+                    .iter()
                     .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
                     .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
                     .collect();
@@ -166,46 +166,42 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                         fundamental: adt_def.is_fundamental(),
                     },
                 });
-                return struct_datum;
+                struct_datum
             }
-            RustDefId::Ref(_) => {
-                return Arc::new(chalk_rust_ir::StructDatum {
-                    id: struct_id,
-                    binders: chalk_ir::Binders::new(
-                        chalk_ir::ParameterKinds::from(
-                            &self.interner,
-                            vec![
-                                chalk_ir::ParameterKind::Lifetime(()),
-                                chalk_ir::ParameterKind::Ty(()),
-                            ],
-                        ),
-                        chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
+            RustDefId::Ref(_) => Arc::new(chalk_rust_ir::StructDatum {
+                id: struct_id,
+                binders: chalk_ir::Binders::new(
+                    chalk_ir::ParameterKinds::from(
+                        &self.interner,
+                        vec![
+                            chalk_ir::ParameterKind::Lifetime(()),
+                            chalk_ir::ParameterKind::Ty(()),
+                        ],
                     ),
-                    flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
-                });
-            }
-            RustDefId::Array | RustDefId::Slice => {
-                return Arc::new(chalk_rust_ir::StructDatum {
-                    id: struct_id,
-                    binders: chalk_ir::Binders::new(
-                        chalk_ir::ParameterKinds::from(
-                            &self.interner,
-                            Some(chalk_ir::ParameterKind::Ty(())),
-                        ),
-                        chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
+                    chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
+                ),
+                flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
+            }),
+            RustDefId::Array | RustDefId::Slice => Arc::new(chalk_rust_ir::StructDatum {
+                id: struct_id,
+                binders: chalk_ir::Binders::new(
+                    chalk_ir::ParameterKinds::from(
+                        &self.interner,
+                        Some(chalk_ir::ParameterKind::Ty(())),
                     ),
-                    flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
-                });
-            }
+                    chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
+                ),
+                flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
+            }),
             RustDefId::Str | RustDefId::Never | RustDefId::FnDef(_) => {
-                return Arc::new(chalk_rust_ir::StructDatum {
+                Arc::new(chalk_rust_ir::StructDatum {
                     id: struct_id,
                     binders: chalk_ir::Binders::new(
                         chalk_ir::ParameterKinds::new(&self.interner),
                         chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
                     ),
                     flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
-                });
+                })
             }
 
             _ => bug!("Used not struct variant when expecting struct variant."),
@@ -228,7 +224,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
         let predicates = self.tcx.predicates_of(def_id).predicates;
         let where_clauses: Vec<_> = predicates
-            .into_iter()
+            .iter()
             .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
 
@@ -260,7 +256,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         // not there yet.
 
         let all_impls = self.tcx.all_impls(def_id);
-        let matched_impls = all_impls.into_iter().filter(|impl_def_id| {
+        let matched_impls = all_impls.filter(|impl_def_id| {
             use chalk_ir::could_match::CouldMatch;
             let trait_ref = self.tcx.impl_trait_ref(*impl_def_id).unwrap();
             let bound_vars = bound_vars_for_item(self.tcx, *impl_def_id);
@@ -304,7 +300,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 _ => {}
             }
         }
-        return false;
+        false
     }
 
     fn associated_ty_value(
@@ -379,7 +375,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                                     ty::AdtKind::Struct | ty::AdtKind::Union => None,
                                     ty::AdtKind::Enum => {
                                         let constraint = self.tcx.adt_sized_constraint(adt_def_id);
-                                        if constraint.0.len() > 0 {
+                                        if !constraint.0.is_empty() {
                                             unimplemented!()
                                         } else {
                                             Some(true)
@@ -412,7 +408,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                                     ty::AdtKind::Struct | ty::AdtKind::Union => None,
                                     ty::AdtKind::Enum => {
                                         let constraint = self.tcx.adt_sized_constraint(adt_def_id);
-                                        if constraint.0.len() > 0 {
+                                        if !constraint.0.is_empty() {
                                             unimplemented!()
                                         } else {
                                             Some(true)
diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs
index 4dc15a6b2b6..aacbd311d1d 100644
--- a/src/librustc_traits/chalk/lowering.rs
+++ b/src/librustc_traits/chalk/lowering.rs
@@ -274,7 +274,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
         let uint = |i| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Uint(i)), empty());
         let float = |f| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Float(f)), empty());
 
-        return match self.kind {
+        match self.kind {
             Bool => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Bool), empty()),
             Char => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Char), empty()),
             Int(ty) => match ty {
@@ -353,7 +353,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
                 apply(chalk_ir::TypeName::Tuple(substs.len()), substs.lower_into(interner))
             }
             Projection(proj) => TyData::Alias(proj.lower_into(interner)).intern(interner),
-            UnnormalizedProjection(_proj) => unimplemented!(),
             Opaque(_def_id, _substs) => unimplemented!(),
             // This should have been done eagerly prior to this, and all Params
             // should have been substituted to placeholders
@@ -370,7 +369,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
             .intern(interner),
             Infer(_infer) => unimplemented!(),
             Error => unimplemented!(),
-        };
+        }
     }
 }
 
diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs
index 76ff58d61a2..08475d6a09d 100644
--- a/src/librustc_traits/dropck_outlives.rs
+++ b/src/librustc_traits/dropck_outlives.rs
@@ -271,8 +271,6 @@ fn dtorck_constraint_for_ty<'tcx>(
             constraints.dtorck_types.push(ty);
         }
 
-        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
         ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => {
             // By the time this code runs, all type variables ought to
             // be fully resolved.
diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs
index 6add099e75b..1aa11a761c8 100644
--- a/src/librustc_ty/ty.rs
+++ b/src/librustc_ty/ty.rs
@@ -47,8 +47,6 @@ fn sized_constraint_for_ty<'tcx>(
             vec![ty]
         }
 
-        UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
         Param(..) => {
             // perf hack: if there is a `T: Sized` bound, then
             // we know that `T` is Sized and do not need to check
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 981e6d2c47e..46d6706cbf4 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -115,7 +115,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::Foreign(..) => Some(PointerKind::Thin),
             // We should really try to normalize here.
             ty::Projection(ref pi) => Some(PointerKind::OfProjection(pi)),
-            ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
             ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)),
             ty::Param(ref p) => Some(PointerKind::OfParam(p)),
             // Insufficient type information.
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 035e5880dc5..87a6f119acb 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -6,7 +6,7 @@ use crate::astconv::AstConv;
 use crate::middle::region;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items;
+use rustc_hir::lang_items::{FutureTraitLangItem, GeneratorTraitLangItem};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::infer::{InferOk, InferResult};
@@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let trait_ref = projection.to_poly_trait_ref(tcx);
 
         let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
-        let gen_trait = tcx.require_lang_item(lang_items::GeneratorTraitLangItem, cause_span);
+        let gen_trait = tcx.require_lang_item(GeneratorTraitLangItem, cause_span);
         let is_gen = gen_trait == trait_ref.def_id();
         if !is_fn && !is_gen {
             debug!("deduce_sig_from_projection: not fn or generator");
@@ -678,7 +678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Check that this is a projection from the `Future` trait.
         let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
-        let future_trait = self.tcx.lang_items().future_trait().unwrap();
+        let future_trait = self.tcx.require_lang_item(FutureTraitLangItem, Some(cause_span));
         if trait_ref.def_id != future_trait {
             debug!("deduce_future_output_from_projection: not a future");
             return None;
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 8ae5ee4c3f9..9694ce9450c 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -7,6 +7,7 @@ use rustc_trait_selection::traits::{self, ObligationCause};
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
+use rustc_hir::lang_items::{CloneTraitLangItem, DerefTraitLangItem};
 use rustc_hir::{is_range_literal, Node};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
@@ -455,8 +456,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
                 if self.can_coerce(ref_ty, expected) {
                     let mut sugg_sp = sp;
-                    if let hir::ExprKind::MethodCall(segment, _sp, args) = &expr.kind {
-                        let clone_trait = self.tcx.lang_items().clone_trait().unwrap();
+                    if let hir::ExprKind::MethodCall(ref segment, sp, ref args) = expr.kind {
+                        let clone_trait = self.tcx.require_lang_item(CloneTraitLangItem, Some(sp));
                         if let ([arg], Some(true), sym::clone) = (
                             &args[..],
                             self.tables.borrow().type_dependent_def_id(expr.hir_id).map(|did| {
@@ -634,7 +635,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ if sp == expr.span && !is_macro => {
                 // Check for `Deref` implementations by constructing a predicate to
                 // prove: `<T as Deref>::Output == U`
-                let deref_trait = self.tcx.lang_items().deref_trait().unwrap();
+                let deref_trait = self.tcx.require_lang_item(DerefTraitLangItem, Some(sp));
                 let item_def_id = self
                     .tcx
                     .associated_items(deref_trait)
@@ -708,24 +709,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // For now, don't suggest casting with `as`.
         let can_cast = false;
 
-        let mut prefix = String::new();
-        if let Some(hir::Node::Expr(hir::Expr {
-            kind: hir::ExprKind::Struct(_, fields, _), ..
+        let prefix = if let Some(hir::Node::Expr(hir::Expr {
+            kind: hir::ExprKind::Struct(_, fields, _),
+            ..
         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
         {
             // `expr` is a literal field for a struct, only suggest if appropriate
-            for field in *fields {
-                if field.expr.hir_id == expr.hir_id && field.is_shorthand {
-                    // This is a field literal
-                    prefix = format!("{}: ", field.ident);
-                    break;
-                }
-            }
-            if &prefix == "" {
+            match (*fields)
+                .iter()
+                .find(|field| field.expr.hir_id == expr.hir_id && field.is_shorthand)
+            {
+                // This is a field literal
+                Some(field) => format!("{}: ", field.ident),
                 // Likely a field was meant, but this field wasn't found. Do not suggest anything.
-                return false;
+                None => return false,
             }
-        }
+        } else {
+            String::new()
+        };
         if let hir::ExprKind::Call(path, args) = &expr.kind {
             if let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
                 (&path.kind, args.len())
@@ -817,7 +818,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let suggest_to_change_suffix_or_into =
                 |err: &mut DiagnosticBuilder<'_>, is_fallible: bool| {
-                    let into_sugg = into_suggestion.clone();
                     err.span_suggestion(
                         expr.span,
                         if literal_is_ty_suffixed(expr) {
@@ -832,7 +832,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         } else if is_fallible {
                             try_into_suggestion
                         } else {
-                            into_sugg
+                            into_suggestion.clone()
                         },
                         Applicability::MachineApplicable,
                     );
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 05028ff0b2c..db6c30adb04 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -69,7 +69,7 @@ fn equate_intrinsic_type<'tcx>(
 /// Returns `true` if the given intrinsic is unsafe to call or not.
 pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
     match intrinsic {
-        "size_of" | "min_align_of" | "needs_drop" | "caller_location" | "size_of_val"
+        "abort" | "size_of" | "min_align_of" | "needs_drop" | "caller_location" | "size_of_val"
         | "min_align_of_val" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow"
         | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
         | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
@@ -130,7 +130,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             }
         };
         (n_tps, inputs, output, hir::Unsafety::Unsafe)
-    } else if &name[..] == "abort" || &name[..] == "unreachable" {
+    } else if &name[..] == "abort" {
+        (0, Vec::new(), tcx.types.never, hir::Unsafety::Normal)
+    } else if &name[..] == "unreachable" {
         (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
     } else {
         let unsafety = intrinsic_operation_unsafety(&name[..]);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index bd8f628957d..200263728d9 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -100,7 +100,9 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::lang_items;
+use rustc_hir::lang_items::{
+    FutureTraitLangItem, PinTypeLangItem, SizedTraitLangItem, VaListTypeLangItem,
+};
 use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
@@ -831,13 +833,6 @@ fn primary_body_of(
 }
 
 fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    // FIXME(#71104) some `LocalDefId` do not seem to have a corresponding `HirId`.
-    if let Some(def_id) = def_id.as_local() {
-        if tcx.hir().opt_local_def_id_to_hir_id(def_id).is_none() {
-            return false;
-        }
-    }
-
     // Closures' tables come from their outermost function,
     // as they are part of the same "inference environment".
     let outer_def_id = tcx.closure_base_def_id(def_id);
@@ -1342,10 +1337,8 @@ fn check_fn<'a, 'tcx>(
     // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
     // (as it's created inside the body itself, not passed in from outside).
     let maybe_va_list = if fn_sig.c_variadic {
-        let va_list_did = tcx.require_lang_item(
-            lang_items::VaListTypeLangItem,
-            Some(body.params.last().unwrap().span),
-        );
+        let va_list_did =
+            tcx.require_lang_item(VaListTypeLangItem, Some(body.params.last().unwrap().span));
         let region = tcx.mk_region(ty::ReScope(region::Scope {
             id: body.value.hir_id.local_id,
             data: region::ScopeData::CallSite,
@@ -1645,81 +1638,78 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
         fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
             debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
-            self.ty = Some(t);
-            if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
+            if t != self.opaque_identity_ty && t.super_visit_with(self) {
+                self.ty = Some(t);
+                return true;
+            }
+            false
         }
 
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
             debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
             if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
-                let found_lifetime = *index < self.generics.parent_count as u32;
-                if !found_lifetime {
-                    self.ty = None;
-                }
-                return found_lifetime;
+                return *index < self.generics.parent_count as u32;
             }
 
             r.super_visit_with(self)
         }
     }
 
-    let mut visitor = ProhibitOpaqueVisitor {
-        opaque_identity_ty: tcx.mk_opaque(
-            def_id.to_def_id(),
-            InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
-        ),
-        generics: tcx.generics_of(def_id),
-        ty: None,
-    };
-    debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
-
-    let prohibit_opaque = match item.kind {
-        ItemKind::OpaqueTy(hir::OpaqueTy {
-            origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
-            ..
-        }) => tcx
+    if let ItemKind::OpaqueTy(hir::OpaqueTy {
+        origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
+        ..
+    }) = item.kind
+    {
+        let mut visitor = ProhibitOpaqueVisitor {
+            opaque_identity_ty: tcx.mk_opaque(
+                def_id.to_def_id(),
+                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+            ),
+            generics: tcx.generics_of(def_id),
+            ty: None,
+        };
+        let prohibit_opaque = tcx
             .predicates_of(def_id)
             .predicates
             .iter()
-            .any(|(predicate, _)| predicate.visit_with(&mut visitor)),
-        _ => false,
-    };
-    debug!(
-        "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
-        prohibit_opaque, visitor
-    );
+            .any(|(predicate, _)| predicate.visit_with(&mut visitor));
+        debug!(
+            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
+            prohibit_opaque, visitor
+        );
 
-    if prohibit_opaque {
-        let is_async = match item.kind {
-            ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
-                hir::OpaqueTyOrigin::AsyncFn => true,
-                _ => false,
-            },
-            _ => unreachable!(),
-        };
+        if prohibit_opaque {
+            let is_async = match item.kind {
+                ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
+                    hir::OpaqueTyOrigin::AsyncFn => true,
+                    _ => false,
+                },
+                _ => unreachable!(),
+            };
 
-        let mut err = struct_span_err!(
-            tcx.sess,
-            span,
-            E0755,
-            "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
+            let mut err = struct_span_err!(
+                tcx.sess,
+                span,
+                E0755,
+                "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
              a parent scope",
-            if is_async { "async fn" } else { "impl Trait" },
-        );
+                if is_async { "async fn" } else { "impl Trait" },
+            );
 
-        if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-            if snippet == "Self" {
-                if let Some(ty) = visitor.ty {
-                    err.span_suggestion(
-                        span,
-                        "consider spelling out the type instead",
-                        format!("{:?}", ty),
-                        Applicability::MaybeIncorrect,
-                    );
+            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
+                if snippet == "Self" {
+                    if let Some(ty) = visitor.ty {
+                        err.span_suggestion(
+                            span,
+                            "consider spelling out the type instead",
+                            format!("{:?}", ty),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
             }
+            err.emit();
         }
-        err.emit();
     }
 }
 
@@ -3326,7 +3316,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         code: traits::ObligationCauseCode<'tcx>,
     ) {
         if !ty.references_error() {
-            let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
+            let lang_item = self.tcx.require_lang_item(SizedTraitLangItem, None);
             self.require_type_meets(ty, span, code, lang_item);
         }
     }
@@ -5165,7 +5155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => {}
         }
         let boxed_found = self.tcx.mk_box(found);
-        let new_found = self.tcx.mk_lang_item(boxed_found, lang_items::PinTypeLangItem).unwrap();
+        let new_found = self.tcx.mk_lang_item(boxed_found, PinTypeLangItem).unwrap();
         if let (true, Ok(snippet)) = (
             self.can_coerce(new_found, expected),
             self.sess().source_map().span_to_snippet(expr.span),
@@ -5312,6 +5302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
     ) {
+        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
         // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
         // body isn't `async`.
         let item_id = self.tcx().hir().get_parent_node(self.body_id);
@@ -5321,7 +5312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let sp = expr.span;
                 // Check for `Future` implementations by constructing a predicate to
                 // prove: `<T as Future>::Output == U`
-                let future_trait = self.tcx.lang_items().future_trait().unwrap();
+                let future_trait = self.tcx.require_lang_item(FutureTraitLangItem, Some(sp));
                 let item_def_id = self
                     .tcx
                     .associated_items(future_trait)
@@ -5329,22 +5320,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .next()
                     .unwrap()
                     .def_id;
+                // `<T as Future>::Output`
+                let projection_ty = ty::ProjectionTy {
+                    // `T`
+                    substs: self
+                        .tcx
+                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
+                    // `Future::Output`
+                    item_def_id,
+                };
+
                 let predicate =
                     ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
-                        // `<T as Future>::Output`
-                        projection_ty: ty::ProjectionTy {
-                            // `T`
-                            substs: self.tcx.mk_substs_trait(
-                                found,
-                                self.fresh_substs_for_item(sp, item_def_id),
-                            ),
-                            // `Future::Output`
-                            item_def_id,
-                        },
+                        projection_ty,
                         ty: expected,
                     }));
                 let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
+
                 debug!("suggest_missing_await: trying obligation {:?}", obligation);
+
                 if self.infcx.predicate_may_hold(&obligation) {
                     debug!("suggest_missing_await: obligation held: {:?}", obligation);
                     if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index c01c4d90c8e..efa3cd9955b 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -4,7 +4,9 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::lang_items::UnsizeTraitLangItem;
+use rustc_hir::lang_items::{
+    CoerceUnsizedTraitLangItem, DispatchFromDynTraitLangItem, UnsizeTraitLangItem,
+};
 use rustc_hir::ItemKind;
 use rustc_infer::infer;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -145,11 +147,11 @@ fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'tcx>, impl_did: LocalDefI
 fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
 
-    let dispatch_from_dyn_trait = tcx.lang_items().dispatch_from_dyn_trait().unwrap();
-
     let impl_hir_id = tcx.hir().as_local_hir_id(impl_did);
     let span = tcx.hir().span(impl_hir_id);
 
+    let dispatch_from_dyn_trait = tcx.require_lang_item(DispatchFromDynTraitLangItem, Some(span));
+
     let source = tcx.type_of(impl_did);
     assert!(!source.has_escaping_bound_vars());
     let target = {
@@ -314,22 +316,23 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
 
 pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
     debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
-    let coerce_unsized_trait = tcx.lang_items().coerce_unsized_trait().unwrap();
+
+    // this provider should only get invoked for local def-ids
+    let impl_hir_id = tcx.hir().as_local_hir_id(impl_did.expect_local());
+    let span = tcx.hir().span(impl_hir_id);
+
+    let coerce_unsized_trait = tcx.require_lang_item(CoerceUnsizedTraitLangItem, Some(span));
 
     let unsize_trait = tcx.lang_items().require(UnsizeTraitLangItem).unwrap_or_else(|err| {
         tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
     });
 
-    // this provider should only get invoked for local def-ids
-    let impl_hir_id = tcx.hir().as_local_hir_id(impl_did.expect_local());
-
     let source = tcx.type_of(impl_did);
     let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
     let target = trait_ref.substs.type_at(1);
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
 
-    let span = tcx.hir().span(impl_hir_id);
     let param_env = tcx.param_env(impl_did);
     assert!(!source.has_escaping_bound_vars());
 
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 01d077d47f0..3a680f55c8c 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -344,11 +344,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 // types, where we use Error as the Self type
             }
 
-            ty::Placeholder(..)
-            | ty::UnnormalizedProjection(..)
-            | ty::GeneratorWitness(..)
-            | ty::Bound(..)
-            | ty::Infer(..) => {
+            ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => {
                 bug!(
                     "unexpected type encountered in \
                       variance inference: {}",
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 8cd9ab41aa4..6c001bc5484 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1722,7 +1722,6 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
             ty::Bound(..) => panic!("Bound"),
             ty::Placeholder(..) => panic!("Placeholder"),
-            ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"),
             ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
             ty::Infer(..) => panic!("Infer"),
             ty::Error => panic!("Error"),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 8bf811877a6..38123816527 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -643,6 +643,15 @@ impl Attributes {
             })
             .collect()
     }
+
+    pub fn get_doc_aliases(&self) -> FxHashSet<String> {
+        self.other_attrs
+            .lists(sym::doc)
+            .filter(|a| a.check_name(sym::alias))
+            .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", "")))
+            .filter(|v| !v.is_empty())
+            .collect::<FxHashSet<_>>()
+    }
 }
 
 impl PartialEq for Attributes {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index a5a1e20396c..5dbcc5c9ec8 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -447,7 +447,7 @@ impl Options {
             None => return Err(3),
         };
 
-        match matches.opt_str("r").as_ref().map(|s| &**s) {
+        match matches.opt_str("r").as_deref() {
             Some("rust") | None => {}
             Some(s) => {
                 diag.struct_err(&format!("unknown input format: {}", s)).emit();
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 51ad1f04340..bf59b3f2573 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -129,7 +129,7 @@ impl<'tcx> DocContext<'tcx> {
         );
 
         MAX_DEF_ID.with(|m| {
-            m.borrow_mut().entry(def_id.krate.clone()).or_insert(start_def_id);
+            m.borrow_mut().entry(def_id.krate).or_insert(start_def_id);
         });
 
         self.all_fake_def_ids.borrow_mut().insert(def_id);
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 0922c8cdd12..ea65b390527 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -114,7 +114,6 @@ pub fn render<T: Print, S: Print>(
         window.rootPath = \"{root_path}\";\
         window.currentCrate = \"{krate}\";\
     </script>\
-    <script src=\"{root_path}aliases{suffix}.js\"></script>\
     <script src=\"{static_root_path}main{suffix}.js\"></script>\
     {static_extra_scripts}\
     {extra_scripts}\
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 550f672ed4c..c129e54c0f2 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -44,7 +44,7 @@ use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
 mod tests;
 
 fn opts() -> Options {
-    Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES
+    Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH
 }
 
 /// When `to_string` is called, this struct will emit the HTML corresponding to
@@ -933,7 +933,11 @@ impl MarkdownSummaryLine<'_> {
             }
         };
 
-        let p = Parser::new_with_broken_link_callback(md, Options::empty(), Some(&replacer));
+        let p = Parser::new_with_broken_link_callback(
+            md,
+            Options::ENABLE_STRIKETHROUGH,
+            Some(&replacer),
+        );
 
         let mut s = String::new();
 
@@ -975,7 +979,11 @@ pub fn plain_summary_line(md: &str) -> String {
         }
     }
     let mut s = String::with_capacity(md.len() * 3 / 2);
-    let p = ParserWrapper { inner: Parser::new(md), is_in: 0, is_first: true };
+    let p = ParserWrapper {
+        inner: Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH),
+        is_in: 0,
+        is_first: true,
+    };
     p.filter(|t| !t.is_empty()).for_each(|i| s.push_str(&i));
     s
 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 4ad9651d563..646c663ad9c 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -293,7 +293,12 @@ impl Serialize for IndexItem {
     where
         S: Serializer,
     {
-        assert_eq!(self.parent.is_some(), self.parent_idx.is_some());
+        assert_eq!(
+            self.parent.is_some(),
+            self.parent_idx.is_some(),
+            "`{}` is missing idx",
+            self.name
+        );
 
         (self.ty, &self.name, &self.path, &self.desc, self.parent_idx, &self.search_type)
             .serialize(serializer)
@@ -796,7 +801,7 @@ themePicker.onblur = handleThemeButtonsBlur;
         if path.exists() {
             for line in BufReader::new(File::open(path)?).lines() {
                 let line = line?;
-                if !line.starts_with("\"") {
+                if !line.starts_with('"') {
                     continue;
                 }
                 if line.starts_with(&format!("\"{}\"", krate)) {
@@ -810,8 +815,7 @@ themePicker.onblur = handleThemeButtonsBlur;
                 }
                 krates.push(
                     line.split('"')
-                        .filter(|s| !s.is_empty())
-                        .next()
+                        .find(|s| !s.is_empty())
                         .map(|s| s.to_owned())
                         .unwrap_or_else(String::new),
                 );
@@ -820,42 +824,6 @@ themePicker.onblur = handleThemeButtonsBlur;
         Ok((ret, krates))
     }
 
-    fn show_item(item: &IndexItem, krate: &str) -> String {
-        format!(
-            "{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}",
-            krate,
-            item.ty as usize,
-            item.name,
-            item.desc.replace("'", "\\'"),
-            item.path,
-            if let Some(p) = item.parent_idx { format!(",'parent':{}", p) } else { String::new() }
-        )
-    }
-
-    let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix));
-    {
-        let (mut all_aliases, _) = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst);
-        let mut output = String::with_capacity(100);
-        for (alias, items) in &cx.cache.aliases {
-            if items.is_empty() {
-                continue;
-            }
-            output.push_str(&format!(
-                "\"{}\":[{}],",
-                alias,
-                items.iter().map(|v| show_item(v, &krate.name)).collect::<Vec<_>>().join(",")
-            ));
-        }
-        all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output));
-        all_aliases.sort();
-        let mut v = Buffer::html();
-        writeln!(&mut v, "var ALIASES = {{}};");
-        for aliases in &all_aliases {
-            writeln!(&mut v, "{}", aliases);
-        }
-        cx.shared.fs.write(&dst, v.into_inner().into_bytes())?;
-    }
-
     use std::ffi::OsString;
 
     #[derive(Debug)]
@@ -2281,7 +2249,10 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
             );
             message.push_str(&format!(": {}", html.to_string()));
         }
-        stability.push(format!("<div class='stab deprecated'>{}</div>", message));
+        stability.push(format!(
+            "<div class='stab deprecated'><span class='emoji'>👎</span> {}</div>",
+            message,
+        ));
     }
 
     if let Some(stab) = item.stability.as_ref().filter(|stab| stab.level == stability::Unstable) {
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 5b090291227..57d385de320 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -120,7 +120,7 @@ crate struct Cache {
 
     /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
     /// we need the alias element to have an array of items.
-    pub(super) aliases: FxHashMap<String, Vec<IndexItem>>,
+    pub(super) aliases: BTreeMap<String, Vec<usize>>,
 }
 
 impl Cache {
@@ -311,7 +311,7 @@ impl DocFolder for Cache {
             };
 
             match parent {
-                (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => {
+                (parent, Some(path)) if is_inherent_impl_item || !self.stripped_mod => {
                     debug_assert!(!item.is_stripped());
 
                     // A crate has a module at its root, containing all items,
@@ -327,6 +327,13 @@ impl DocFolder for Cache {
                             parent_idx: None,
                             search_type: get_index_search_type(&item),
                         });
+
+                        for alias in item.attrs.get_doc_aliases() {
+                            self.aliases
+                                .entry(alias.to_lowercase())
+                                .or_insert(Vec::new())
+                                .push(self.search_index.len() - 1);
+                        }
                     }
                 }
                 (Some(parent), None) if is_inherent_impl_item => {
@@ -376,11 +383,8 @@ impl DocFolder for Cache {
                 {
                     self.paths.insert(item.def_id, (self.stack.clone(), item.type_()));
                 }
-                self.add_aliases(&item);
             }
-
             clean::PrimitiveItem(..) => {
-                self.add_aliases(&item);
                 self.paths.insert(item.def_id, (self.stack.clone(), item.type_()));
             }
 
@@ -488,40 +492,6 @@ impl DocFolder for Cache {
     }
 }
 
-impl Cache {
-    fn add_aliases(&mut self, item: &clean::Item) {
-        if item.def_id.index == CRATE_DEF_INDEX {
-            return;
-        }
-        if let Some(ref item_name) = item.name {
-            let path = self
-                .paths
-                .get(&item.def_id)
-                .map(|p| p.0[..p.0.len() - 1].join("::"))
-                .unwrap_or("std".to_owned());
-            for alias in item
-                .attrs
-                .lists(sym::doc)
-                .filter(|a| a.check_name(sym::alias))
-                .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", "")))
-                .filter(|v| !v.is_empty())
-                .collect::<FxHashSet<_>>()
-                .into_iter()
-            {
-                self.aliases.entry(alias).or_insert(Vec::with_capacity(1)).push(IndexItem {
-                    ty: item.type_(),
-                    name: item_name.to_string(),
-                    path: path.clone(),
-                    desc: shorten(plain_summary_line(item.doc_value())),
-                    parent: None,
-                    parent_idx: None,
-                    search_type: get_index_search_type(&item),
-                });
-            }
-        }
-    }
-}
-
 /// Attempts to find where an external crate is located, given that we're
 /// rendering in to the specified source destination.
 fn extern_location(
@@ -567,7 +537,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     let mut crate_items = Vec::with_capacity(cache.search_index.len());
     let mut crate_paths = vec![];
 
-    let Cache { ref mut search_index, ref orphan_impl_items, ref paths, .. } = *cache;
+    let Cache { ref mut search_index, ref orphan_impl_items, ref paths, ref mut aliases, .. } =
+        *cache;
 
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
@@ -582,6 +553,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
                 parent_idx: None,
                 search_type: get_index_search_type(&item),
             });
+            for alias in item.attrs.get_doc_aliases() {
+                aliases
+                    .entry(alias.to_lowercase())
+                    .or_insert(Vec::new())
+                    .push(search_index.len() - 1);
+            }
         }
     }
 
@@ -630,6 +607,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
         items: Vec<&'a IndexItem>,
         #[serde(rename = "p")]
         paths: Vec<(ItemType, String)>,
+        // The String is alias name and the vec is the list of the elements with this alias.
+        //
+        // To be noted: the `usize` elements are indexes to `items`.
+        #[serde(rename = "a")]
+        #[serde(skip_serializing_if = "BTreeMap::is_empty")]
+        aliases: &'a BTreeMap<String, Vec<usize>>,
     }
 
     // Collect the index into a string
@@ -640,6 +623,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
             doc: crate_doc,
             items: crate_items,
             paths: crate_paths,
+            aliases,
         })
         .expect("failed serde conversion")
         // All these `replace` calls are because we have to go through JS string for JSON content.
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index a023d5a2d95..9b498d66249 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -531,6 +531,7 @@ function getSearchElement() {
         var OUTPUT_DATA = 1;
         var NO_TYPE_FILTER = -1;
         var currentResults, index, searchIndex;
+        var ALIASES = {};
         var params = getQueryStringParams();
 
         // Populate search bar with query string search term when provided,
@@ -963,6 +964,72 @@ function getSearchElement() {
                 return itemTypes[ty.ty] + ty.path + ty.name;
             }
 
+            function createAliasFromItem(item) {
+                return {
+                    crate: item.crate,
+                    name: item.name,
+                    path: item.path,
+                    desc: item.desc,
+                    ty: item.ty,
+                    parent: item.parent,
+                    type: item.type,
+                    is_alias: true,
+                };
+            }
+
+            function handleAliases(ret, query, filterCrates) {
+                // We separate aliases and crate aliases because we want to have current crate
+                // aliases to be before the others in the displayed results.
+                var aliases = [];
+                var crateAliases = [];
+                var i;
+                if (filterCrates !== undefined &&
+                        ALIASES[filterCrates] &&
+                        ALIASES[filterCrates][query.search]) {
+                    for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
+                        aliases.push(
+                            createAliasFromItem(searchIndex[ALIASES[filterCrates][query.search]]));
+                    }
+                } else {
+                    Object.keys(ALIASES).forEach(function(crate) {
+                        if (ALIASES[crate][query.search]) {
+                            var pushTo = crate === window.currentCrate ? crateAliases : aliases;
+                            for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
+                                pushTo.push(
+                                    createAliasFromItem(
+                                        searchIndex[ALIASES[crate][query.search][i]]));
+                            }
+                        }
+                    });
+                }
+
+                var sortFunc = function(aaa, bbb) {
+                    if (aaa.path < bbb.path) {
+                        return 1;
+                    } else if (aaa.path === bbb.path) {
+                        return 0;
+                    }
+                    return -1;
+                };
+                crateAliases.sort(sortFunc);
+                aliases.sort(sortFunc);
+
+                var pushFunc = function(alias) {
+                    alias.alias = query.raw;
+                    var res = buildHrefAndPath(alias);
+                    alias.displayPath = pathSplitter(res[0]);
+                    alias.fullPath = alias.displayPath + alias.name;
+                    alias.href = res[1];
+
+                    ret.others.unshift(alias);
+                    if (ret.others.length > MAX_RESULTS) {
+                        ret.others.pop();
+                    }
+                };
+                onEach(aliases, pushFunc);
+                onEach(crateAliases, pushFunc);
+            }
+
             // quoted values mean literal search
             var nSearchWords = searchWords.length;
             var i;
@@ -1190,23 +1257,7 @@ function getSearchElement() {
                 "returned": sortResults(results_returned, true),
                 "others": sortResults(results),
             };
-            if (ALIASES && ALIASES[window.currentCrate] &&
-                    ALIASES[window.currentCrate][query.raw]) {
-                var aliases = ALIASES[window.currentCrate][query.raw];
-                for (i = 0; i < aliases.length; ++i) {
-                    aliases[i].is_alias = true;
-                    aliases[i].alias = query.raw;
-                    aliases[i].path = aliases[i].p;
-                    var res = buildHrefAndPath(aliases[i]);
-                    aliases[i].displayPath = pathSplitter(res[0]);
-                    aliases[i].fullPath = aliases[i].displayPath + aliases[i].name;
-                    aliases[i].href = res[1];
-                    ret.others.unshift(aliases[i]);
-                    if (ret.others.length > MAX_RESULTS) {
-                        ret.others.pop();
-                    }
-                }
-            }
+            handleAliases(ret, query, filterCrates);
             return ret;
         }
 
@@ -1599,13 +1650,12 @@ function getSearchElement() {
                     "returned": mergeArrays(results.returned),
                     "others": mergeArrays(results.others),
                 };
-            } else {
-                return {
-                    "in_args": results.in_args[0],
-                    "returned": results.returned[0],
-                    "others": results.others[0],
-                };
             }
+            return {
+                "in_args": results.in_args[0],
+                "returned": results.returned[0],
+                "others": results.others[0],
+            };
         }
 
         function getFilterCrates() {
@@ -1656,10 +1706,13 @@ function getSearchElement() {
             searchIndex = [];
             var searchWords = [];
             var i;
+            var currentIndex = 0;
 
             for (var crate in rawSearchIndex) {
                 if (!rawSearchIndex.hasOwnProperty(crate)) { continue; }
 
+                var crateSize = 0;
+
                 searchWords.push(crate);
                 searchIndex.push({
                     crate: crate,
@@ -1669,6 +1722,7 @@ function getSearchElement() {
                     desc: rawSearchIndex[crate].doc,
                     type: null,
                 });
+                currentIndex += 1;
 
                 // an array of [(Number) item type,
                 //              (String) name,
@@ -1680,6 +1734,9 @@ function getSearchElement() {
                 // an array of [(Number) item type,
                 //              (String) name]
                 var paths = rawSearchIndex[crate].p;
+                // a array of [(String) alias name
+                //             [Number] index to items]
+                var aliases = rawSearchIndex[crate].a;
 
                 // convert `rawPaths` entries into object form
                 var len = paths.length;
@@ -1698,9 +1755,18 @@ function getSearchElement() {
                 var lastPath = "";
                 for (i = 0; i < len; ++i) {
                     var rawRow = items[i];
-                    var row = {crate: crate, ty: rawRow[0], name: rawRow[1],
-                               path: rawRow[2] || lastPath, desc: rawRow[3],
-                               parent: paths[rawRow[4]], type: rawRow[5]};
+                    if (!rawRow[2]) {
+                        rawRow[2] = lastPath;
+                    }
+                    var row = {
+                        crate: crate,
+                        ty: rawRow[0],
+                        name: rawRow[1],
+                        path: rawRow[2],
+                        desc: rawRow[3],
+                        parent: paths[rawRow[4]],
+                        type: rawRow[5],
+                    };
                     searchIndex.push(row);
                     if (typeof row.name === "string") {
                         var word = row.name.toLowerCase();
@@ -1709,7 +1775,25 @@ function getSearchElement() {
                         searchWords.push("");
                     }
                     lastPath = row.path;
+                    crateSize += 1;
+                }
+
+                if (aliases) {
+                    ALIASES[crate] = {};
+                    var j, local_aliases;
+                    for (var alias_name in aliases) {
+                        if (!aliases.hasOwnProperty(alias_name)) { continue; }
+
+                        if (!ALIASES[crate].hasOwnProperty(alias_name)) {
+                            ALIASES[crate][alias_name] = [];
+                        }
+                        local_aliases = aliases[alias_name];
+                        for (j = 0; j < local_aliases.length; ++j) {
+                            ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
+                        }
+                    }
                 }
+                currentIndex += crateSize;
             }
             return searchWords;
         }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index fbdb538cd87..a3ef350a048 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -12,7 +12,8 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::ty;
 use rustc_resolve::ParentScope;
 use rustc_session::lint;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Ident;
+use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
 
 use std::ops::Range;
@@ -130,6 +131,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         current_item: &Option<String>,
         parent_id: Option<hir::HirId>,
         extra_fragment: &Option<String>,
+        item_opt: Option<&Item>,
     ) -> Result<(Res, Option<String>), ErrorKind> {
         let cx = self.cx;
 
@@ -230,16 +232,44 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias,
                     did,
                 ) => {
-                    let item = cx
-                        .tcx
-                        .inherent_impls(did)
-                        .iter()
-                        .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
-                        .find(|item| item.ident.name == item_name);
+                    // We need item's parent to know if it's
+                    // trait impl or struct/enum/etc impl
+                    let item_parent = item_opt
+                        .and_then(|item| self.cx.as_local_hir_id(item.def_id))
+                        .and_then(|item_hir| {
+                            let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
+                            self.cx.tcx.hir().find(parent_hir)
+                        });
+                    let item = match item_parent {
+                        Some(hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. },
+                            ..
+                        })) => {
+                            // trait impl
+                            cx.tcx
+                                .associated_item_def_ids(self_ty.hir_id.owner)
+                                .iter()
+                                .map(|child| {
+                                    let associated_item = cx.tcx.associated_item(*child);
+                                    associated_item
+                                })
+                                .find(|child| child.ident.name == item_name)
+                        }
+                        _ => {
+                            // struct/enum/etc. impl
+                            cx.tcx
+                                .inherent_impls(did)
+                                .iter()
+                                .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
+                                .find(|item| item.ident.name == item_name)
+                        }
+                    };
+
                     if let Some(item) = item {
                         let out = match item.kind {
                             ty::AssocKind::Fn if ns == ValueNS => "method",
                             ty::AssocKind::Const if ns == ValueNS => "associatedconstant",
+                            ty::AssocKind::Type if ns == ValueNS => "associatedtype",
                             _ => return self.variant_field(path_str, current_item, module_id),
                         };
                         if extra_fragment.is_some() {
@@ -484,8 +514,14 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
                 match kind {
                     Some(ns @ ValueNS) => {
-                        match self.resolve(path_str, ns, &current_item, base_node, &extra_fragment)
-                        {
+                        match self.resolve(
+                            path_str,
+                            ns,
+                            &current_item,
+                            base_node,
+                            &extra_fragment,
+                            None,
+                        ) {
                             Ok(res) => res,
                             Err(ErrorKind::ResolutionFailure) => {
                                 resolution_failure(cx, &item, path_str, &dox, link_range);
@@ -501,8 +537,14 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                         }
                     }
                     Some(ns @ TypeNS) => {
-                        match self.resolve(path_str, ns, &current_item, base_node, &extra_fragment)
-                        {
+                        match self.resolve(
+                            path_str,
+                            ns,
+                            &current_item,
+                            base_node,
+                            &extra_fragment,
+                            None,
+                        ) {
                             Ok(res) => res,
                             Err(ErrorKind::ResolutionFailure) => {
                                 resolution_failure(cx, &item, path_str, &dox, link_range);
@@ -526,6 +568,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                                 &current_item,
                                 base_node,
                                 &extra_fragment,
+                                None,
                             ) {
                                 Err(ErrorKind::AnchorFailure(msg)) => {
                                     anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
@@ -539,6 +582,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                                 &current_item,
                                 base_node,
                                 &extra_fragment,
+                                Some(&item),
                             ) {
                                 Err(ErrorKind::AnchorFailure(msg)) => {
                                     anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 4a9ad39e236..a00c9a0bcea 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -255,8 +255,7 @@ fn run_test(
 
     let rustc_binary = options
         .test_builder
-        .as_ref()
-        .map(|v| &**v)
+        .as_deref()
         .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc"));
     let mut compiler = Command::new(&rustc_binary);
     compiler.arg("--crate-type").arg("bin");
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index c0011fddf4f..7261d631a6f 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -10,7 +10,7 @@ Core encoding and decoding interfaces.
     test(attr(allow(unused_variables), deny(warnings)))
 )]
 #![feature(box_syntax)]
-#![feature(specialization)]
+#![feature(specialization)] // FIXME: min_specialization does not work
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index e6da7426eb4..56cf9be3391 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -251,6 +251,9 @@ impl<K, V, S> HashMap<K, V, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -261,6 +264,8 @@ impl<K, V, S> HashMap<K, V, S> {
     /// let mut map = HashMap::with_hasher(s);
     /// map.insert(1, 2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
@@ -278,6 +283,9 @@ impl<K, V, S> HashMap<K, V, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -288,6 +296,8 @@ impl<K, V, S> HashMap<K, V, S> {
     /// let mut map = HashMap::with_capacity_and_hasher(10, s);
     /// map.insert(1, 2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index c1a57f2ce61..ca06457291c 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -273,6 +273,9 @@ impl<T, S> HashSet<T, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -283,6 +286,8 @@ impl<T, S> HashSet<T, S> {
     /// let mut set = HashSet::with_hasher(s);
     /// set.insert(2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hasher: S) -> HashSet<T, S> {
@@ -300,6 +305,9 @@ impl<T, S> HashSet<T, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -310,6 +318,8 @@ impl<T, S> HashSet<T, S> {
     /// let mut set = HashSet::with_capacity_and_hasher(10, s);
     /// set.insert(1);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 4fde3316973..7a05aaf71f2 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -4,6 +4,7 @@ use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::ops;
 use crate::rc::Rc;
+use crate::str::FromStr;
 use crate::sync::Arc;
 
 use crate::sys::os_str::{Buf, Slice};
@@ -1174,6 +1175,15 @@ impl AsInner<Slice> for OsStr {
     }
 }
 
+#[stable(feature = "osstring_from_str", since = "1.45.0")]
+impl FromStr for OsString {
+    type Err = core::convert::Infallible;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(OsString::from(s))
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 343b2ee1273..bf381896a22 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -332,7 +332,10 @@ pub fn panicking() -> bool {
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
-        unsafe { intrinsics::abort() }
+        #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
+        unsafe {
+            intrinsics::abort()
+        }
     }
 
     let info = PanicInfo::internal_constructor(Some(msg), Location::caller());
@@ -398,7 +401,10 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
 #[track_caller]
 pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
-        unsafe { intrinsics::abort() }
+        #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
+        unsafe {
+            intrinsics::abort()
+        }
     }
 
     rust_panic_with_hook(&mut PanicPayload::new(msg), None, Location::caller());
@@ -458,7 +464,10 @@ fn rust_panic_with_hook(
             "thread panicked while processing \
                                        panic. aborting.\n"
         ));
-        unsafe { intrinsics::abort() }
+        #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
+        unsafe {
+            intrinsics::abort()
+        }
     }
 
     unsafe {
@@ -493,7 +502,10 @@ fn rust_panic_with_hook(
             "thread panicked while panicking. \
                                        aborting.\n"
         ));
-        unsafe { intrinsics::abort() }
+        #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
+        unsafe {
+            intrinsics::abort()
+        }
     }
 
     rust_panic(payload)
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 173d6d1cfa7..8516e80f3b8 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -157,10 +157,10 @@ pub enum Prefix<'a> {
         #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
     ),
 
-    /// Verbatim disk prefix, e.g., `\\?\C:\`.
+    /// Verbatim disk prefix, e.g., `\\?\C:`.
     ///
     /// Verbatim disk prefixes consist of `\\?\` immediately followed by the
-    /// drive letter and `:\`.
+    /// drive letter and `:`.
     #[stable(feature = "rust1", since = "1.0.0")]
     VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8),
 
diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs
index fd9d61e99c2..d1a46c51757 100644
--- a/src/libstd/sync/mpsc/shared.rs
+++ b/src/libstd/sync/mpsc/shared.rs
@@ -354,6 +354,8 @@ impl<T> Packet<T> {
 
         // See comments on Arc::clone() on why we do this (for `mem::forget`).
         if old_count > MAX_REFCOUNT {
+            // remove `unsafe` on bootstrap bump
+            #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
             unsafe {
                 abort();
             }
diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs
index 79123903e92..603764922c5 100644
--- a/src/libstd/sync/mpsc/sync.rs
+++ b/src/libstd/sync/mpsc/sync.rs
@@ -358,6 +358,8 @@ impl<T> Packet<T> {
 
         // See comments on Arc::clone() on why we do this (for `mem::forget`).
         if old_count > MAX_REFCOUNT {
+            // remove `unsafe` on bootstrap bump
+            #[cfg_attr(not(bootstrap), allow(unused_unsafe))]
             unsafe {
                 abort();
             }
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 7a3cbbe4562..3134a596756 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -737,6 +737,8 @@ pub fn panicking() -> bool {
 /// The thread may sleep longer than the duration specified due to scheduling
 /// specifics or platform-dependent functionality. It will never sleep less.
 ///
+/// This function is blocking, and should not be used in `async` functions.
+///
 /// # Platform-specific behavior
 ///
 /// On Unix platforms, the underlying syscall may be interrupted by a
@@ -763,6 +765,8 @@ pub fn sleep_ms(ms: u32) {
 /// The thread may sleep longer than the duration specified due to scheduling
 /// specifics or platform-dependent functionality. It will never sleep less.
 ///
+/// This function is blocking, and should not be used in `async` functions.
+///
 /// # Platform-specific behavior
 ///
 /// On Unix platforms, the underlying syscall may be interrupted by a
@@ -1272,7 +1276,7 @@ impl Thread {
     }
 
     fn cname(&self) -> Option<&CStr> {
-        self.inner.name.as_ref().map(|s| &**s)
+        self.inner.name.as_deref()
     }
 }
 
diff --git a/src/libtest/cli.rs b/src/libtest/cli.rs
index aac454c023c..0cec8050c27 100644
--- a/src/libtest/cli.rs
+++ b/src/libtest/cli.rs
@@ -331,7 +331,7 @@ fn get_format(
     quiet: bool,
     allow_unstable: bool,
 ) -> OptPartRes<OutputFormat> {
-    let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
+    let format = match matches.opt_str("format").as_deref() {
         None if quiet => OutputFormat::Terse,
         Some("pretty") | None => OutputFormat::Pretty,
         Some("terse") => OutputFormat::Terse,
@@ -355,7 +355,7 @@ fn get_format(
 }
 
 fn get_color_config(matches: &getopts::Matches) -> OptPartRes<ColorConfig> {
-    let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
+    let color = match matches.opt_str("color").as_deref() {
         Some("auto") | None => ColorConfig::AutoColor,
         Some("always") => ColorConfig::AlwaysColor,
         Some("never") => ColorConfig::NeverColor,
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 84bde9a52f7..b17fa57c5c1 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -717,7 +717,7 @@ LLVMRustOptimizeWithNewPassManager(
     LLVMRustOptStage OptStage,
     bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
     bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
-    bool DisableSimplifyLibCalls,
+    bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
     LLVMRustSanitizerOptions *SanitizerOptions,
     const char *PGOGenPath, const char *PGOUsePath,
     void* LlvmSelfProfiler,
@@ -853,7 +853,7 @@ LLVMRustOptimizeWithNewPassManager(
         MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
       }
 
-      MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/false));
+      MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
 
 #if LLVM_VERSION_GE(10, 0)
       if (PGOOpt) {
diff --git a/src/stdarch b/src/stdarch
-Subproject d10eefc62284c40c5a95a2eed19fc1f414a5364
+Subproject ec6fccd34c30003a7ebf4e7a9dfe4e31f5b76e1
diff --git a/src/test/codegen/target-feature-multiple.rs b/src/test/codegen/target-feature-multiple.rs
new file mode 100644
index 00000000000..f71a9c3c582
--- /dev/null
+++ b/src/test/codegen/target-feature-multiple.rs
@@ -0,0 +1,9 @@
+// only-x86_64
+// compile-flags: -C target-feature=+sse2,-avx,+avx2 -C target-feature=+avx,-avx2
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: attributes #0 = { {{.*}}"target-features"="+sse2,-avx,+avx2,+avx,-avx2"{{.*}} }
+}
diff --git a/src/test/incremental/const-generics/issue-62536.rs b/src/test/incremental/const-generics/issue-62536.rs
index 90e279bfc74..0eaeb910be6 100644
--- a/src/test/incremental/const-generics/issue-62536.rs
+++ b/src/test/incremental/const-generics/issue-62536.rs
@@ -1,6 +1,6 @@
 // revisions:cfail1
 #![feature(const_generics)]
-//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//[cfail1]~^ WARN the feature `const_generics` is incomplete
 
 struct S<T, const N: usize>([T; N]);
 
diff --git a/src/test/incremental/const-generics/issue-64087.rs b/src/test/incremental/const-generics/issue-64087.rs
index b3c12fbb6e8..6b10c540494 100644
--- a/src/test/incremental/const-generics/issue-64087.rs
+++ b/src/test/incremental/const-generics/issue-64087.rs
@@ -1,6 +1,6 @@
 // revisions:cfail1
 #![feature(const_generics)]
-//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//[cfail1]~^ WARN the feature `const_generics` is incomplete
 
 fn combinator<T, const S: usize>() -> [T; S] {}
 //[cfail1]~^ ERROR mismatched types
diff --git a/src/test/mir-opt/byte_slice/rustc.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/byte_slice/rustc.main.SimplifyCfg-elaborate-drops.after.mir
index b8ecaf787fe..88cb09ac15a 100644
--- a/src/test/mir-opt/byte_slice/rustc.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/byte_slice/rustc.main.SimplifyCfg-elaborate-drops.after.mir
@@ -16,10 +16,10 @@ fn main() -> () {
         _1 = const b"foo";               // scope 0 at $DIR/byte_slice.rs:5:13: 5:19
                                          // ty::Const
                                          // + ty: &[u8; 3]
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/byte_slice.rs:5:13: 5:19
-                                         // + literal: Const { ty: &[u8; 3], val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &[u8; 3], val: Value(Scalar(alloc0)) }
         StorageLive(_2);                 // scope 1 at $DIR/byte_slice.rs:6:9: 6:10
         _2 = [const 5u8, const 120u8];   // scope 1 at $DIR/byte_slice.rs:6:13: 6:24
                                          // ty::Const
diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir
index d202531c7ab..509947071b0 100644
--- a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir
+++ b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR-promoted[0].ConstProp.after.mir
@@ -7,13 +7,13 @@ promoted[0] in BAR: &[&i32; 1] = {
     let mut _3: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
 
     bb0: {
-        _3 = const {alloc0+0x0: &i32};   // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
+        _3 = const {alloc0: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
-                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) }
         _2 = _3;                         // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34
         _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
         _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff
index d517207390d..8eb8d4c667b 100644
--- a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff
+++ b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff
@@ -16,16 +16,16 @@
 -         StorageLive(_3);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 -         StorageLive(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34
 -         StorageLive(_5);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
--         _5 = const {alloc0+0x0: &i32};   // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
+-         _5 = const {alloc0: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
 +         _6 = const BAR::promoted[0];     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
                                            // ty::Const
 -                                          // + ty: &i32
--                                          // + val: Value(Scalar(alloc0+0x0))
+-                                          // + val: Value(Scalar(alloc0))
 +                                          // + ty: &[&i32; 1]
 +                                          // + val: Unevaluated(DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
--                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc0+0x0)) }
+-                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) }
 -         _4 = &(*_5);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir
index b49c1aaa866..d9c6b4f0029 100644
--- a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir
+++ b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO-promoted[0].ConstProp.after.mir
@@ -9,13 +9,13 @@ promoted[0] in FOO: &[&i32; 1] = {
     }
 
     bb0: {
-        _3 = const {alloc2+0x0: &i32};   // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+        _3 = const {alloc2: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Value(Scalar(alloc2+0x0))
+                                         // + val: Value(Scalar(alloc2))
                                          // mir::Constant
                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
-                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc2+0x0)) }
+                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
         _2 = _3;                         // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
         _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
         _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff
index 09c08cf449f..781aa3c5500 100644
--- a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff
@@ -18,16 +18,16 @@
 -         StorageLive(_3);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         StorageLive(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
 -         StorageLive(_5);                 // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
--         _5 = const {alloc2+0x0: &i32};   // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+-         _5 = const {alloc2: &i32};       // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 +         _6 = const FOO::promoted[0];     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
                                            // ty::Const
 -                                          // + ty: &i32
--                                          // + val: Value(Scalar(alloc2+0x0))
+-                                          // + val: Value(Scalar(alloc2))
 +                                          // + ty: &[&i32; 1]
 +                                          // + val: Unevaluated(DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
--                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc2+0x0)) }
+-                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
 -         _4 = &(*_5);                     // scope 1 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
diff --git a/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir
index a20dd7bf0fc..30a383fd162 100644
--- a/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir
+++ b/src/test/mir-opt/const_allocation/32bit/rustc.main.ConstProp.after.mir
@@ -8,13 +8,13 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
-        _2 = const {alloc0+0x0: &&[(std::option::Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
+        _2 = const {alloc0: &&[(std::option::Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
                                          // ty::Const
                                          // + ty: &&[(std::option::Option<i32>, &[&str])]
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation.rs:8:5: 8:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc0)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
@@ -30,19 +30,19 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 8, align: 4) {
-    ╾─a17+0x0─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc17─╼ 03 00 00 00                         │ ╾──╼....
 }
 
 alloc17 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─a4+0x0──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─a8+0x0──╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─a13+0x0─╼ 03 00 00 00 │ ....*...╾──╼....
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc4──╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
 alloc4 (size: 0, align: 4) {}
 
 alloc8 (size: 16, align: 4) {
-    ╾─a7+0x0──╼ 03 00 00 00 ╾─a9+0x0──╼ 03 00 00 00 │ ╾──╼....╾──╼....
+    ╾─alloc7──╼ 03 00 00 00 ╾─alloc9──╼ 03 00 00 00 │ ╾──╼....╾──╼....
 }
 
 alloc7 (size: 3, align: 1) {
@@ -54,8 +54,8 @@ alloc9 (size: 3, align: 1) {
 }
 
 alloc13 (size: 24, align: 4) {
-    0x00 │ ╾─a12+0x0─╼ 03 00 00 00 ╾─a14+0x0─╼ 03 00 00 00 │ ╾──╼....╾──╼....
-    0x10 │ ╾─a15+0x0─╼ 04 00 00 00                         │ ╾──╼....
+    0x00 │ ╾─alloc12─╼ 03 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+    0x10 │ ╾─alloc15─╼ 04 00 00 00                         │ ╾──╼....
 }
 
 alloc12 (size: 3, align: 1) {
diff --git a/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir
index ff89ac9ad93..5fa54ae5a58 100644
--- a/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir
+++ b/src/test/mir-opt/const_allocation/64bit/rustc.main.ConstProp.after.mir
@@ -8,13 +8,13 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
-        _2 = const {alloc0+0x0: &&[(std::option::Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
+        _2 = const {alloc0: &&[(std::option::Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
                                          // ty::Const
                                          // + ty: &&[(std::option::Option<i32>, &[&str])]
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation.rs:8:5: 8:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc0)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
@@ -30,22 +30,22 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 16, align: 8) {
-    ╾─────alloc17+0x0─────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc17───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 alloc17 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─────alloc4+0x0──────╼ │ ....░░░░╾──────╼
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc4────────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾─────alloc8+0x0──────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾─────alloc13+0x0─────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
 alloc4 (size: 0, align: 8) {}
 
 alloc8 (size: 32, align: 8) {
-    0x00 │ ╾─────alloc7+0x0──────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾─────alloc9+0x0──────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x00 │ ╾───────alloc7────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 alloc7 (size: 3, align: 1) {
@@ -57,9 +57,9 @@ alloc9 (size: 3, align: 1) {
 }
 
 alloc13 (size: 48, align: 8) {
-    0x00 │ ╾─────alloc12+0x0─────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾─────alloc14+0x0─────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x20 │ ╾─────alloc15+0x0─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x00 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x20 │ ╾───────alloc15───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 alloc12 (size: 3, align: 1) {
diff --git a/src/test/mir-opt/const_allocation2/32bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation2/32bit/rustc.main.ConstProp.after.mir
index e392eaa6aed..d386d247829 100644
--- a/src/test/mir-opt/const_allocation2/32bit/rustc.main.ConstProp.after.mir
+++ b/src/test/mir-opt/const_allocation2/32bit/rustc.main.ConstProp.after.mir
@@ -8,13 +8,13 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
-        _2 = const {alloc0+0x0: &&[(std::option::Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
+        _2 = const {alloc0: &&[(std::option::Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
                                          // ty::Const
                                          // + ty: &&[(std::option::Option<i32>, &[&u8])]
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation2.rs:5:5: 5:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc0)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
@@ -30,19 +30,19 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 8, align: 4) {
-    ╾─a21+0x0─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc21─╼ 03 00 00 00                         │ ╾──╼....
 }
 
 alloc21 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─a4+0x0──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─a9+0x0──╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─a19+0x0─╼ 03 00 00 00 │ ....*...╾──╼....
+    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 │ ....*...╾──╼....
 }
 
 alloc4 (size: 0, align: 4) {}
 
 alloc9 (size: 8, align: 4) {
-    ╾─a7+0x0──╼ ╾─a8+0x0──╼                         │ ╾──╼╾──╼
+    ╾─alloc7──╼ ╾─alloc8──╼                         │ ╾──╼╾──╼
 }
 
 alloc7 (size: 1, align: 1) {
@@ -54,7 +54,7 @@ alloc8 (size: 1, align: 1) {
 }
 
 alloc19 (size: 12, align: 4) {
-    ╾─a15+0x3─╼ ╾─a16+0x0─╼ ╾─a18+0x2─╼             │ ╾──╼╾──╼╾──╼
+    ╾─a15+0x3─╼ ╾─alloc16─╼ ╾─a18+0x2─╼             │ ╾──╼╾──╼╾──╼
 }
 
 alloc15 (size: 4, align: 1) {
diff --git a/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir
index 81dc0372b5d..d7acd0f0f43 100644
--- a/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir
+++ b/src/test/mir-opt/const_allocation2/64bit/rustc.main.ConstProp.after.mir
@@ -8,13 +8,13 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
-        _2 = const {alloc0+0x0: &&[(std::option::Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
+        _2 = const {alloc0: &&[(std::option::Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
                                          // ty::Const
                                          // + ty: &&[(std::option::Option<i32>, &[&u8])]
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation2.rs:5:5: 5:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc0)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
@@ -30,21 +30,21 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 16, align: 8) {
-    ╾─────alloc21+0x0─────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc21───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 alloc21 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─────alloc4+0x0──────╼ │ ....░░░░╾──────╼
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc4────────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾─────alloc9+0x0──────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾─────alloc19+0x0─────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc9────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc19───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
 alloc4 (size: 0, align: 8) {}
 
 alloc9 (size: 16, align: 8) {
-    ╾─────alloc7+0x0──────╼ ╾─────alloc8+0x0──────╼ │ ╾──────╼╾──────╼
+    ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼
 }
 
 alloc7 (size: 1, align: 1) {
@@ -56,7 +56,7 @@ alloc8 (size: 1, align: 1) {
 }
 
 alloc19 (size: 24, align: 8) {
-    0x00 │ ╾─────alloc15+0x3─────╼ ╾─────alloc16+0x0─────╼ │ ╾──────╼╾──────╼
+    0x00 │ ╾─────alloc15+0x3─────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼
     0x10 │ ╾─────alloc18+0x2─────╼                         │ ╾──────╼
 }
 
diff --git a/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir
index a29327eb973..39c60ad987a 100644
--- a/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir
+++ b/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir
@@ -8,13 +8,13 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
-        _2 = const {alloc0+0x0: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
+        _2 = const {alloc0: &&Packed};   // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
                                          // ty::Const
                                          // + ty: &&Packed
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation3.rs:5:5: 5:8
-                                         // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc0)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9
@@ -30,19 +30,19 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 4, align: 4) {
-    ╾─a9+0x0──╼                                     │ ╾──╼
+    ╾─alloc9──╼                                     │ ╾──╼
 }
 
 alloc9 (size: 168, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─a4+0x0──╼ │ ............╾──╼
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼
     0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─a6+0x0──╼ 00 00 │ ..........╾──╼..
+    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc6──╼ 00 00 │ ..........╾──╼..
     0x90 │ ╾─a7+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
     0xa0 │ 00 00 00 00 00 00 00 00                         │ ........
 }
diff --git a/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir
index 865c7c93432..96024f1c82c 100644
--- a/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir
+++ b/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir
@@ -8,13 +8,13 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
-        _2 = const {alloc0+0x0: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
+        _2 = const {alloc0: &&Packed};   // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
                                          // ty::Const
                                          // + ty: &&Packed
-                                         // + val: Value(Scalar(alloc0+0x0))
+                                         // + val: Value(Scalar(alloc0))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation3.rs:5:5: 5:8
-                                         // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc0+0x0)) }
+                                         // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc0)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9
@@ -30,12 +30,12 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 8, align: 8) {
-    ╾─────alloc9+0x0──────╼                         │ ╾──────╼
+    ╾───────alloc9────────╼                         │ ╾──────╼
 }
 
 alloc9 (size: 180, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾alloc4+0x0 │ ............╾───
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾───
     0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
@@ -43,7 +43,7 @@ alloc9 (size: 180, align: 1) {
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─
-    0x90 │ ───alloc6+0x0───╼ 00 00 ╾─────alloc7+0x63─────╼ │ ─────╼..╾──────╼
+    0x90 │ ─────alloc6─────╼ 00 00 ╾─────alloc7+0x63─────╼ │ ─────╼..╾──────╼
     0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0xb0 │ 00 00 00 00                                     │ ....
 }
diff --git a/src/test/mir-opt/const_prop/mutable_variable.rs b/src/test/mir-opt/const_prop/mutable_variable.rs
new file mode 100644
index 00000000000..b3a2d80fa95
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = 42;
+    x = 99;
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..187c1745435
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
@@ -0,0 +1,52 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable.rs:4:11: 4:11
+      let mut _1: i32;                     // in scope 0 at $DIR/mutable_variable.rs:5:9: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable.rs:5:9: 5:14
+          let _2: i32;                     // in scope 1 at $DIR/mutable_variable.rs:7:9: 7:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/mutable_variable.rs:7:9: 7:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable.rs:5:9: 5:14
+          _1 = const 42i32;                // scope 0 at $DIR/mutable_variable.rs:5:17: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002a))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable.rs:5:17: 5:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+          _1 = const 99i32;                // scope 1 at $DIR/mutable_variable.rs:6:5: 6:11
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000063))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable.rs:6:9: 6:11
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10
+-         _2 = _1;                         // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
++         _2 = const 99i32;                // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000063))
++                                          // mir::Constant
++                                          // + span: $DIR/mutable_variable.rs:7:13: 7:14
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable.rs:4:11: 8:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable.rs:4:11: 8:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable.rs:8:1: 8:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/mutable_variable.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
new file mode 100644
index 00000000000..3c5fb4574b6
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = (42, 43);
+    x.1 = 99;
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..cf432b2acc1
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
@@ -0,0 +1,66 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_aggregate.rs:4:11: 4:11
+      let mut _1: (i32, i32);              // in scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
+          let _2: (i32, i32);              // in scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
+          _1 = (const 42i32, const 43i32); // 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
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+                                           // 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
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
+          (_1.1: i32) = const 99i32;       // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000063))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
+-         _2 = _1;                         // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++         _2 = (const 42i32, const 99i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x0000002a))
++                                          // mir::Constant
++                                          // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000063))
++                                          // mir::Constant
++                                          // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_aggregate.rs:4:11: 8:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate.rs:4:11: 8:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/mutable_variable_aggregate.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
new file mode 100644
index 00000000000..fc13cbf2abd
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
@@ -0,0 +1,9 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = (42, 43);
+    let z = &mut x;
+    z.1 = 99;
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..44203ac327a
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff
@@ -0,0 +1,58 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 4:11
+      let mut _1: (i32, i32);              // in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
+          let _2: &mut (i32, i32);         // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
+          scope 2 {
+              debug z => _2;               // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
+              let _3: (i32, i32);          // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10
+              scope 3 {
+                  debug y => _3;           // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
+          _1 = (const 42i32, const 43i32); // 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)) }
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002b))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
+          _2 = &mut _1;                    // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19
+          ((*_2).1: i32) = const 99i32;    // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:7:5: 7:13
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000063))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:7:11: 7:13
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10
+          _3 = _1;                         // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:13: 8:14
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 9:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 9:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:2: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
new file mode 100644
index 00000000000..4f43ec8c947
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
@@ -0,0 +1,14 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x: (i32, i32) = foo();
+    x.1 = 99;
+    x.0 = 42;
+    let y = x.1;
+}
+
+#[inline(never)]
+fn foo() -> (i32, i32) {
+    unimplemented!()
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..6834bb6bdd4
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff
@@ -0,0 +1,62 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 4:11
+      let mut _1: (i32, i32) as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14
+          let _2: i32;                     // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14
+          _1 = const foo() -> bb1;         // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:34
+                                           // ty::Const
+                                           // + ty: fn() -> (i32, i32) {foo}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32
+                                           // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          (_1.1: i32) = const 99i32;       // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:6:5: 6:13
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000063))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:6:11: 6:13
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          (_1.0: i32) = const 42i32;       // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:7:5: 7:13
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002a))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:7:11: 7:13
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10
+-         _2 = (_1.1: i32);                // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
++         _2 = const 99i32;                // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000063))
++                                          // mir::Constant
++                                          // + span: $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 9:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 9:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:9:1: 9:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:9:2: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
new file mode 100644
index 00000000000..8c9cd005096
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
@@ -0,0 +1,12 @@
+// compile-flags: -O
+
+static mut STATIC: u32 = 42;
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = 42;
+    unsafe {
+        x = STATIC;
+    }
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..b7f1242d8d1
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff
@@ -0,0 +1,69 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_no_prop.rs:6:11: 6:11
+      let mut _1: u32;                     // in scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
+      let _2: ();                          // in scope 0 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+      let mut _3: u32;                     // in scope 0 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+      let mut _4: *mut u32;                // in scope 0 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
+          let _5: u32;                     // in scope 1 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10
+          scope 2 {
+          }
+          scope 3 {
+              debug y => _5;               // in scope 3 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
+          _1 = const 42u32;                // scope 0 at $DIR/mutable_variable_no_prop.rs:7:17: 7:19
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x0000002a))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:7:17: 7:19
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+          StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+          StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+          _4 = const {alloc0: *mut u32};   // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+                                           // ty::Const
+                                           // + ty: *mut u32
+                                           // + val: Value(Scalar(alloc0))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+                                           // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc0)) }
+          _3 = (*_4);                      // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+          _1 = move _3;                    // scope 2 at $DIR/mutable_variable_no_prop.rs:9:9: 9:19
+          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:18: 9:19
+          StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:19: 9:20
+          _2 = const ();                   // scope 2 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:10:5: 10:6
+          StorageLive(_5);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10
+          _5 = _1;                         // scope 1 at $DIR/mutable_variable_no_prop.rs:11:13: 11:14
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_no_prop.rs:6:11: 12:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:6:11: 12:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_5);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2
+          return;                          // scope 0 at $DIR/mutable_variable_no_prop.rs:12:2: 12:2
+      }
+  }
+  
+  alloc0 (static: STATIC, size: 4, align: 4) {
+      2a 00 00 00                                     │ *...
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
new file mode 100644
index 00000000000..40f801b1b5e
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let a = foo();
+    let mut x: (i32, i32) = (1, 2);
+    x.1 = a;
+    let y = x.1;
+    let z = x.0; // this could theoretically be allowed, but we can't handle it right now
+}
+
+#[inline(never)]
+fn foo() -> i32 {
+    unimplemented!()
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..738343c655e
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff
@@ -0,0 +1,74 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_unprop_assign.rs:4:11: 4:11
+      let _1: i32;                         // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10
+      let mut _3: i32;                     // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10
+          let mut _2: (i32, i32) as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14
+          scope 2 {
+              debug x => _2;               // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14
+              let _4: i32;                 // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:8:9: 8:10
+              scope 3 {
+                  debug y => _4;           // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:8:9: 8:10
+                  let _5: i32;             // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:9: 9:10
+                  scope 4 {
+                      debug z => _5;       // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:9:9: 9:10
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10
+          _1 = const foo() -> bb1;         // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:13: 5:18
+                                           // ty::Const
+                                           // + ty: fn() -> i32 {foo}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16
+                                           // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14
+          _2 = (const 1i32, const 2i32);   // 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
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+                                           // 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
+                                           // + 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
+          (_2.1: i32) = move _3;           // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:5: 7:12
+          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12
+          StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:8:9: 8:10
+          _4 = (_2.1: i32);                // scope 2 at $DIR/mutable_variable_unprop_assign.rs:8:13: 8:16
+          StorageLive(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:9: 9:10
+          _5 = (_2.0: i32);                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:13: 9:16
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_unprop_assign.rs:4:11: 10:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_unprop_assign.rs:4:11: 10:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2
+          StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/mutable_variable_unprop_assign.rs:10:2: 10:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff
index bbe0d106011..103444f796e 100644
--- a/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff
@@ -16,13 +16,13 @@
           StorageLive(_1);                 // scope 0 at $DIR/read_immutable_static.rs:7:9: 7:10
           StorageLive(_2);                 // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
           StorageLive(_3);                 // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
-          _3 = const {alloc0+0x0: &u8};    // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
+          _3 = const {alloc0: &u8};        // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
                                            // ty::Const
                                            // + ty: &u8
-                                           // + val: Value(Scalar(alloc0+0x0))
+                                           // + val: Value(Scalar(alloc0))
                                            // mir::Constant
                                            // + span: $DIR/read_immutable_static.rs:7:13: 7:16
-                                           // + literal: Const { ty: &u8, val: Value(Scalar(alloc0+0x0)) }
+                                           // + literal: Const { ty: &u8, val: Value(Scalar(alloc0)) }
 -         _2 = (*_3);                      // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
 +         _2 = const 2u8;                  // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
 +                                          // ty::Const
@@ -33,13 +33,13 @@
 +                                          // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
           StorageLive(_4);                 // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
           StorageLive(_5);                 // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
-          _5 = const {alloc0+0x0: &u8};    // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
+          _5 = const {alloc0: &u8};        // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
                                            // ty::Const
                                            // + ty: &u8
-                                           // + val: Value(Scalar(alloc0+0x0))
+                                           // + val: Value(Scalar(alloc0))
                                            // mir::Constant
                                            // + span: $DIR/read_immutable_static.rs:7:19: 7:22
-                                           // + literal: Const { ty: &u8, val: Value(Scalar(alloc0+0x0)) }
+                                           // + literal: Const { ty: &u8, val: Value(Scalar(alloc0)) }
 -         _4 = (*_5);                      // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
 -         _1 = Add(move _2, move _4);      // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22
 +         _4 = const 2u8;                  // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff
index b976449ca6d..1e0271a560f 100644
--- a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff
@@ -17,7 +17,7 @@
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000007b))
                                            // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:29:5: 29:12
+                                           // + span: $DIR/copy_propagation_arg.rs:29:9: 29:12
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000007b)) }
           _0 = _2;                         // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
           StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff
index 26f8068f674..b875bbea67b 100644
--- a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff
@@ -28,7 +28,7 @@
                                            // + ty: u8
                                            // + val: Value(Scalar(0x05))
                                            // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:17:5: 17:10
+                                           // + span: $DIR/copy_propagation_arg.rs:17:9: 17:10
                                            // + literal: Const { ty: u8, val: Value(Scalar(0x05)) }
           _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2
                                            // ty::Const
diff --git a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
index bf24bfb2c57..6199e2c5662 100644
--- a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
@@ -35,9 +35,38 @@
                                            // mir::Constant
                                            // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
                                            // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
+          goto -> bb3;                     // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      }
+  
+      bb1: {
+          ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + 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
+      }
+  
+      bb2: {
+          unreachable;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25
+      }
+  
+      bb3: {
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
           _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
-          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:35: 20:36
+          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      }
+  
+      bb4: {
           StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
           _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
                                            // ty::Const
diff --git a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
index ff7183e57d2..bf875c6a555 100644
--- a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
@@ -35,9 +35,38 @@
                                            // mir::Constant
                                            // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
                                            // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
+          goto -> bb3;                     // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      }
+  
+      bb1: {
+          ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + 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
+      }
+  
+      bb2: {
+          unreachable;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25
+      }
+  
+      bb3: {
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
           _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
-          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:35: 20:36
+          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      }
+  
+      bb4: {
           StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
           _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
                                            // ty::Const
diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs
new file mode 100644
index 00000000000..0e3f86501bb
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm.rs
@@ -0,0 +1,32 @@
+// compile-flags: -Z mir-opt-level=1
+// EMIT_MIR rustc.id.SimplifyArmIdentity.diff
+// EMIT_MIR rustc.id.SimplifyBranchSame.diff
+// EMIT_MIR rustc.id_result.SimplifyArmIdentity.diff
+// EMIT_MIR rustc.id_result.SimplifyBranchSame.diff
+// EMIT_MIR rustc.id_try.SimplifyArmIdentity.diff
+// EMIT_MIR rustc.id_try.SimplifyBranchSame.diff
+
+fn id(o: Option<u8>) -> Option<u8> {
+    match o {
+        Some(v) => Some(v),
+        None => None,
+    }
+}
+
+fn id_result(r: Result<u8, i32>) -> Result<u8, i32> {
+    match r {
+        Ok(x) => Ok(x),
+        Err(y) => Err(y),
+    }
+}
+
+fn id_try(r: Result<u8, i32>) -> Result<u8, i32> {
+    let x = r?;
+    Ok(x)
+}
+
+fn main() {
+    id(None);
+    id_result(Ok(4));
+    id_try(Ok(4));
+}
diff --git a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..8d08267d75b
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff
@@ -0,0 +1,45 @@
+- // MIR for `id` before SimplifyArmIdentity
++ // MIR for `id` after SimplifyArmIdentity
+  
+  fn id(_1: std::option::Option<u8>) -> std::option::Option<u8> {
+      debug o => _1;                       // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8
+      let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26
+      scope 1 {
+          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+          switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      }
+  
+      bb1: {
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12
+      }
+  
+      bb3: {
+-         StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+-         _3 = ((_1 as Some).0: u8);       // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+-         StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+-         _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+-         ((_0 as Some).0: u8) = move _4;  // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+-         discriminant(_0) = 1;            // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+-         StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:27: 11:28
++         _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff
new file mode 100644
index 00000000000..23fa9817f80
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff
@@ -0,0 +1,37 @@
+- // MIR for `id` before SimplifyBranchSame
++ // MIR for `id` after SimplifyBranchSame
+  
+  fn id(_1: std::option::Option<u8>) -> std::option::Option<u8> {
+      debug o => _1;                       // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8
+      let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26
+      scope 1 {
+          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+          switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      }
+  
+      bb1: {
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12
+      }
+  
+      bb3: {
+          _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..e2a12ca5be2
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff
@@ -0,0 +1,58 @@
+- // MIR for `id_result` before SimplifyArmIdentity
++ // MIR for `id_result` after SimplifyArmIdentity
+  
+  fn id_result(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:16:14: 16:15
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:16:37: 16:52
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:18:21: 18:22
+      let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+      let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
+      }
+      scope 2 {
+          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+          switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      }
+  
+      bb1: {
+-         StorageLive(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+-         _5 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+-         StorageLive(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+-         _6 = _5;                         // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+-         ((_0 as Err).0: i32) = move _6;  // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+-         discriminant(_0) = 1;            // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+-         StorageDead(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25
+-         StorageDead(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:25: 19:26
++         _0 = move _1;                    // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12
+      }
+  
+      bb3: {
+-         StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+-         _3 = ((_1 as Ok).0: u8);         // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+-         StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+-         _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+-         ((_0 as Ok).0: u8) = move _4;    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+-         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+-         StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:23: 18:24
++         _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff
new file mode 100644
index 00000000000..9d1ff22dc51
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff
@@ -0,0 +1,45 @@
+- // MIR for `id_result` before SimplifyBranchSame
++ // MIR for `id_result` after SimplifyBranchSame
+  
+  fn id_result(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:16:14: 16:15
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:16:37: 16:52
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:18:21: 18:22
+      let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+      let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
+      }
+      scope 2 {
+          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+-         switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
++         goto -> bb1;                     // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      }
+  
+      bb1: {
+-         _0 = move _1;                    // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+-         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+-     }
+- 
+-     bb2: {
+-         unreachable;                     // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12
+-     }
+- 
+-     bb3: {
+          _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+-         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
++         goto -> bb2;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+      }
+  
+-     bb4: {
++     bb2: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..ba6e1ac24cb
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff
@@ -0,0 +1,109 @@
+- // MIR for `id_try` before SimplifyArmIdentity
++ // MIR for `id_try` after SimplifyArmIdentity
+  
+  fn id_try(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49
+      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10
+      }
+      scope 2 {
+          debug err => _6;                 // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15
+          scope 3 {
+          }
+      }
+      scope 4 {
+          debug val => _10;                // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15
+          scope 5 {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _3 = const <std::result::Result<u8, i32> as std::ops::Try>::into_result(move _4) -> bb1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+                                           // ty::Const
+                                           // + ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      }
+  
+      bb2: {
+-         StorageLive(_10);                // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+-         _10 = ((_3 as Ok).0: u8);        // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+-         _2 = _10;                        // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15
+-         StorageDead(_10);                // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
++         _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+-         StorageLive(_11);                // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9
+-         ((_0 as Ok).0: u8) = move _11;   // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+-         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb3: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      }
+  
+      bb4: {
+          StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _9 = _6;                         // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _8 = const <i32 as std::convert::From<i32>>::from(move _9) -> bb5; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:14: 24:15
+                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb5: {
+          StorageDead(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _0 = const <std::result::Result<u8, i32> as std::ops::Try>::from_error(move _8) -> bb6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb6: {
+          StorageDead(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb7: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff
new file mode 100644
index 00000000000..4061c5e74ac
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff
@@ -0,0 +1,100 @@
+- // MIR for `id_try` before SimplifyBranchSame
++ // MIR for `id_try` after SimplifyBranchSame
+  
+  fn id_try(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49
+      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10
+      }
+      scope 2 {
+          debug err => _6;                 // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15
+          scope 3 {
+          }
+      }
+      scope 4 {
+          debug val => _10;                // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15
+          scope 5 {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _3 = const <std::result::Result<u8, i32> as std::ops::Try>::into_result(move _4) -> bb1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+                                           // ty::Const
+                                           // + ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      }
+  
+      bb2: {
+          _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb3: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      }
+  
+      bb4: {
+          StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _9 = _6;                         // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _8 = const <i32 as std::convert::From<i32>>::from(move _9) -> bb5; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:14: 24:15
+                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb5: {
+          StorageDead(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _0 = const <std::result::Result<u8, i32> as std::ops::Try>::from_error(move _8) -> bb6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb6: {
+          StorageDead(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb7: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff
index 009153cfd49..58c5313909f 100644
--- a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff
@@ -15,16 +15,16 @@
       let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
       let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9
       scope 1 {
-          debug y => _10;                  // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+          debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
       }
       scope 2 {
           debug err => _6;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
           scope 3 {
               scope 7 {
-                  debug t => _6;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+                  debug t => _9;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
               }
               scope 8 {
-                  debug v => _6;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+                  debug v => _8;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
                   let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15
               }
           }
@@ -35,31 +35,54 @@
           }
       }
       scope 6 {
-          debug self => _1;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+          debug self => _4;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
       }
   
       bb0: {
-          _5 = discriminant(_1);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+          StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+          _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+          _3 = move _4;                    // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+          StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
           switchInt(move _5) -> [0isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
       }
   
       bb1: {
--         _10 = ((_1 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
--         ((_0 as Ok).0: u32) = move _10;  // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+-         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+-         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+-         _2 = _10;                        // scope 5 at $DIR/simplify_try.rs:6:13: 6:15
+-         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
++         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
+-         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:7:8: 7:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:7:8: 7:9
+-         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
 -         discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-+         _0 = move _1;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-+         nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-+         nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
           goto -> bb3;                     // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
       }
   
       bb2: {
--         _6 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
--         ((_0 as Err).0: i32) = move _6;  // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+-         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageLive(_8);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageLive(_9);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         _9 = _6;                         // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         _8 = move _9;                    // scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+-         StorageDead(_9);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageLive(_12);                // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         _12 = move _8;                   // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
 -         discriminant(_0) = 1;            // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
-+         _0 = move _1;                    // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
-+         nop;                             // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
-+         nop;                             // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         StorageDead(_12);                // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         StorageDead(_8);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
++         _0 = move _3;                    // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
           goto -> bb3;                     // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
       }
   
diff --git a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir
index e5661a47201..be61e5e2a9f 100644
--- a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir
+++ b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir
@@ -14,16 +14,16 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
     let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
     let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9
     scope 1 {
-        debug y => _10;                  // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+        debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
     }
     scope 2 {
         debug err => _6;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
         scope 3 {
             scope 7 {
-                debug t => _6;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+                debug t => _9;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
             }
             scope 8 {
-                debug v => _6;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+                debug v => _8;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
                 let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15
             }
         }
@@ -34,18 +34,24 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
         }
     }
     scope 6 {
-        debug self => _1;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+        debug self => _4;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
     }
 
     bb0: {
-        _5 = discriminant(_1);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
+        StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+        StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+        _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+        _3 = move _4;                    // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+        StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+        _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
         goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
     }
 
     bb1: {
-        _0 = move _1;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-        nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-        nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+        _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+        StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
+        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
         goto -> bb2;                     // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
     }
 
diff --git a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir
index 989931ed0ea..b12036f6a03 100644
--- a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir
+++ b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir
@@ -3,24 +3,27 @@
 fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
     debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18
     let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57
-    let _2: i32;                         // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
-    let _3: u32;                         // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+    let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10
+    let _3: i32;                         // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+    let mut _4: i32;                     // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+    let mut _5: i32;                     // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+    let _6: u32;                         // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
     scope 1 {
-        debug y => _3;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+        debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
     }
     scope 2 {
-        debug err => _2;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
+        debug err => _3;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
         scope 3 {
             scope 7 {
-                debug t => _2;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+                debug t => _5;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
             }
             scope 8 {
-                debug v => _2;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+                debug v => _4;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
             }
         }
     }
     scope 4 {
-        debug val => _3;                 // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
+        debug val => _6;                 // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
         scope 5 {
         }
     }
@@ -29,7 +32,9 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
     }
 
     bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
         _0 = move _1;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
         return;                          // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
     }
 }
diff --git a/src/test/mir-opt/simplify_try_if_let.rs b/src/test/mir-opt/simplify_try_if_let.rs
new file mode 100644
index 00000000000..daa961c3c8c
--- /dev/null
+++ b/src/test/mir-opt/simplify_try_if_let.rs
@@ -0,0 +1,40 @@
+// compile-flags: -Zmir-opt-level=1
+// EMIT_MIR rustc.{{impl}}-append.SimplifyArmIdentity.diff
+
+use std::ptr::NonNull;
+
+pub struct LinkedList {
+    head: Option<NonNull<Node>>,
+    tail: Option<NonNull<Node>>,
+}
+
+pub struct Node {
+    next: Option<NonNull<Node>>,
+}
+
+impl LinkedList {
+    pub fn new() -> Self {
+        Self { head: None, tail: None }
+    }
+
+    pub fn append(&mut self, other: &mut Self) {
+        match self.tail {
+            None => { },
+            Some(mut tail) => {
+                // `as_mut` is okay here because we have exclusive access to the entirety
+                // of both lists.
+                if let Some(other_head) = other.head.take() {
+                    unsafe {
+                        tail.as_mut().next = Some(other_head);
+                    }
+                }
+            }
+        }
+    }
+}
+
+fn main() {
+    let mut one = LinkedList::new();
+    let mut two = LinkedList::new();
+    one.append(&mut two);
+}
diff --git a/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..6ccec937b9b
--- /dev/null
+++ b/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff
@@ -0,0 +1,127 @@
+- // MIR for `<impl at $DIR/simplify_try_if_let.rs:15:1: 34:2>::append` before SimplifyArmIdentity
++ // MIR for `<impl at $DIR/simplify_try_if_let.rs:15:1: 34:2>::append` after SimplifyArmIdentity
+  
+  fn <impl at $DIR/simplify_try_if_let.rs:15:1: 34:2>::append(_1: &mut LinkedList, _2: &mut LinkedList) -> () {
+      debug self => _1;                    // in scope 0 at $DIR/simplify_try_if_let.rs:20:19: 20:28
+      debug other => _2;                   // in scope 0 at $DIR/simplify_try_if_let.rs:20:30: 20:35
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_try_if_let.rs:20:48: 20:48
+      let mut _3: isize;                   // in scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+      let mut _4: std::ptr::NonNull<Node>; // in scope 0 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+      let mut _5: std::option::Option<std::ptr::NonNull<Node>>; // in scope 0 at $DIR/simplify_try_if_let.rs:26:43: 26:60
+      let mut _6: &mut std::option::Option<std::ptr::NonNull<Node>>; // in scope 0 at $DIR/simplify_try_if_let.rs:26:43: 26:53
+      let mut _7: isize;                   // in scope 0 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+      let mut _9: std::option::Option<std::ptr::NonNull<Node>>; // in scope 0 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+      let mut _10: std::ptr::NonNull<Node>; // in scope 0 at $DIR/simplify_try_if_let.rs:28:51: 28:61
+      let mut _11: &mut Node;              // in scope 0 at $DIR/simplify_try_if_let.rs:28:25: 28:38
+      let mut _12: &mut std::ptr::NonNull<Node>; // in scope 0 at $DIR/simplify_try_if_let.rs:28:25: 28:29
+      scope 1 {
+          debug tail => _4;                // in scope 1 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+          let _8: std::ptr::NonNull<Node>; // in scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+          scope 2 {
+              debug other_head => _8;      // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+              scope 3 {
+              }
+          }
+      }
+  
+      bb0: {
+          _3 = discriminant(((*_1).1: std::option::Option<std::ptr::NonNull<Node>>)); // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+          switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+      }
+  
+      bb1: {
+          StorageLive(_4);                 // scope 0 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+          _4 = ((((*_1).1: std::option::Option<std::ptr::NonNull<Node>>) as Some).0: std::ptr::NonNull<Node>); // scope 0 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+          StorageLive(_5);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60
+          StorageLive(_6);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53
+          _6 = &mut ((*_2).0: std::option::Option<std::ptr::NonNull<Node>>); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53
+          _5 = const std::option::Option::<std::ptr::NonNull<Node>>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60
+                                           // ty::Const
+                                           // + ty: for<'r> fn(&'r mut std::option::Option<std::ptr::NonNull<Node>>) -> std::option::Option<std::ptr::NonNull<Node>> {std::option::Option::<std::ptr::NonNull<Node>>::take}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:26:54: 26:58
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::option::Option<std::ptr::NonNull<Node>>) -> std::option::Option<std::ptr::NonNull<Node>> {std::option::Option::<std::ptr::NonNull<Node>>::take}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify_try_if_let.rs:21:15: 21:24
+      }
+  
+      bb3: {
+          _0 = const ();                   // scope 0 at $DIR/simplify_try_if_let.rs:22:21: 22:24
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:22:21: 22:24
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb9;                     // scope 0 at $DIR/simplify_try_if_let.rs:21:9: 32:10
+      }
+  
+      bb4: {
+          StorageDead(_6);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:59: 26:60
+          _7 = discriminant(_5);           // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+          switchInt(move _7) -> [1isize: bb6, otherwise: bb5]; // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+      }
+  
+      bb5: {
+          _0 = const ();                   // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:26:17: 30:18
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb8;                     // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18
+      }
+  
+      bb6: {
+          StorageLive(_8);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+          _8 = ((_5 as Some).0: std::ptr::NonNull<Node>); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+          StorageLive(_9);                 // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+-         StorageLive(_10);                // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61
+-         _10 = _8;                        // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61
+-         ((_9 as Some).0: std::ptr::NonNull<Node>) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+-         discriminant(_9) = 1;            // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+-         StorageDead(_10);                // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62
++         _9 = move _5;                    // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+          StorageLive(_11);                // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38
+          StorageLive(_12);                // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29
+          _12 = &mut _4;                   // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29
+          _11 = const std::ptr::NonNull::<Node>::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38
+                                           // ty::Const
+                                           // + ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull<Node>) -> &'r mut Node {std::ptr::NonNull::<Node>::as_mut}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:28:30: 28:36
+                                           // + literal: Const { ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull<Node>) -> &'r mut Node {std::ptr::NonNull::<Node>::as_mut}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb7: {
+          StorageDead(_12);                // scope 3 at $DIR/simplify_try_if_let.rs:28:37: 28:38
+          ((*_11).0: std::option::Option<std::ptr::NonNull<Node>>) = move _9; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:62
+          StorageDead(_9);                 // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62
+          StorageDead(_11);                // scope 3 at $DIR/simplify_try_if_let.rs:28:62: 28:63
+          _0 = const ();                   // scope 3 at $DIR/simplify_try_if_let.rs:27:21: 29:22
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:27:21: 29:22
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_8);                 // scope 1 at $DIR/simplify_try_if_let.rs:30:17: 30:18
+          goto -> bb8;                     // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18
+      }
+  
+      bb8: {
+          StorageDead(_5);                 // scope 1 at $DIR/simplify_try_if_let.rs:31:13: 31:14
+          StorageDead(_4);                 // scope 0 at $DIR/simplify_try_if_let.rs:32:9: 32:10
+          goto -> bb9;                     // scope 0 at $DIR/simplify_try_if_let.rs:21:9: 32:10
+      }
+  
+      bb9: {
+          return;                          // scope 0 at $DIR/simplify_try_if_let.rs:33:6: 33:6
+      }
+  }
+  
diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js
index f3c6713692b..798fa29efbd 100644
--- a/src/test/rustdoc-js-std/alias-2.js
+++ b/src/test/rustdoc-js-std/alias-2.js
@@ -1,10 +1,10 @@
-// ignore-order
-
 const QUERY = '+';
 
 const EXPECTED = {
     'others': [
         { 'path': 'std::ops', 'name': 'AddAssign' },
         { 'path': 'std::ops', 'name': 'Add' },
+        { 'path': 'core::ops', 'name': 'AddAssign' },
+        { 'path': 'core::ops', 'name': 'Add' },
     ],
 };
diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js
new file mode 100644
index 00000000000..896808d4157
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias.js
@@ -0,0 +1,263 @@
+// exact-check
+
+const QUERY = [
+    'StructItem',
+    'StructFieldItem',
+    'StructMethodItem',
+    'ImplTraitItem',
+    'ImplAssociatedConstItem',
+    'ImplTraitFunction',
+    'EnumItem',
+    'VariantItem',
+    'EnumMethodItem',
+    'TypedefItem',
+    'TraitItem',
+    'TraitTypeItem',
+    'AssociatedConstItem',
+    'TraitFunctionItem',
+    'FunctionItem',
+    'ModuleItem',
+    'ConstItem',
+    'StaticItem',
+    'UnionItem',
+    'UnionFieldItem',
+    'UnionMethodItem',
+    'MacroItem',
+];
+
+const EXPECTED = [
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Struct',
+                'alias': 'StructItem',
+                'href': '../doc_alias/struct.Struct.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Struct',
+                'name': 'field',
+                'alias': 'StructFieldItem',
+                'href': '../doc_alias/struct.Struct.html#structfield.field',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Struct',
+                'name': 'method',
+                'alias': 'StructMethodItem',
+                'href': '../doc_alias/struct.Struct.html#method.method',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        // ImplTraitItem
+        'others': [],
+    },
+    {
+        // ImplAssociatedConstItem
+        'others': [],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Struct',
+                'name': 'function',
+                'alias': 'ImplTraitFunction',
+                'href': '../doc_alias/struct.Struct.html#method.function',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Enum',
+                'alias': 'EnumItem',
+                'href': '../doc_alias/enum.Enum.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Enum',
+                'name': 'Variant',
+                'alias': 'VariantItem',
+                'href': '../doc_alias/enum.Enum.html#variant.Variant',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Enum',
+                'name': 'method',
+                'alias': 'EnumMethodItem',
+                'href': '../doc_alias/enum.Enum.html#method.method',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Typedef',
+                'alias': 'TypedefItem',
+                'href': '../doc_alias/type.Typedef.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Trait',
+                'alias': 'TraitItem',
+                'href': '../doc_alias/trait.Trait.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Trait',
+                'name': 'Target',
+                'alias': 'TraitTypeItem',
+                'href': '../doc_alias/trait.Trait.html#associatedtype.Target',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Trait',
+                'name': 'AssociatedConst',
+                'alias': 'AssociatedConstItem',
+                'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Trait',
+                'name': 'function',
+                'alias': 'TraitFunctionItem',
+                'href': '../doc_alias/trait.Trait.html#tymethod.function',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'function',
+                'alias': 'FunctionItem',
+                'href': '../doc_alias/fn.function.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Module',
+                'alias': 'ModuleItem',
+                'href': '../doc_alias/Module/index.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Const',
+                'alias': 'ConstItem',
+                'href': '../doc_alias/constant.Const.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Static',
+                'alias': 'StaticItem',
+                'href': '../doc_alias/static.Static.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Union',
+                'alias': 'UnionItem',
+                'href': '../doc_alias/union.Union.html',
+                'is_alias': true
+            },
+            // Not an alias!
+            {
+                'path': 'doc_alias::Union',
+                'name': 'union_item',
+                'href': '../doc_alias/union.Union.html#structfield.union_item'
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Union',
+                'name': 'union_item',
+                'alias': 'UnionFieldItem',
+                'href': '../doc_alias/union.Union.html#structfield.union_item',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Union',
+                'name': 'method',
+                'alias': 'UnionMethodItem',
+                'href': '../doc_alias/union.Union.html#method.method',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Macro',
+                'alias': 'MacroItem',
+                'href': '../doc_alias/macro.Macro.html',
+                'is_alias': true
+            },
+        ],
+    },
+];
diff --git a/src/test/rustdoc-js/doc-alias.rs b/src/test/rustdoc-js/doc-alias.rs
new file mode 100644
index 00000000000..84c638a1995
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias.rs
@@ -0,0 +1,79 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "StructItem")]
+pub struct Struct {
+    #[doc(alias = "StructFieldItem")]
+    pub field: u32,
+}
+
+impl Struct {
+    #[doc(alias = "StructMethodItem")]
+    pub fn method(&self) {}
+}
+
+impl Trait for Struct {
+    // Shouldn't be listed in aliases!
+    #[doc(alias = "ImplTraitItem")]
+    type Target = u32;
+    // Shouldn't be listed in aliases!
+    #[doc(alias = "ImplAssociatedConstItem")]
+    const AssociatedConst: i32 = 12;
+
+    #[doc(alias = "ImplTraitFunction")]
+    fn function() -> Self::Target { 0 }
+}
+
+#[doc(alias = "EnumItem")]
+pub enum Enum {
+    #[doc(alias = "VariantItem")]
+    Variant,
+}
+
+impl Enum {
+    #[doc(alias = "EnumMethodItem")]
+    pub fn method(&self) {}
+}
+
+#[doc(alias = "TypedefItem")]
+pub type Typedef = i32;
+
+#[doc(alias = "TraitItem")]
+pub trait Trait {
+    #[doc(alias = "TraitTypeItem")]
+    type Target;
+    #[doc(alias = "AssociatedConstItem")]
+    const AssociatedConst: i32;
+
+    #[doc(alias = "TraitFunctionItem")]
+    fn function() -> Self::Target;
+}
+
+#[doc(alias = "FunctionItem")]
+pub fn function() {}
+
+#[doc(alias = "ModuleItem")]
+pub mod Module {}
+
+#[doc(alias = "ConstItem")]
+pub const Const: u32 = 0;
+
+#[doc(alias = "StaticItem")]
+pub static Static: u32 = 0;
+
+#[doc(alias = "UnionItem")]
+pub union Union {
+    #[doc(alias = "UnionFieldItem")]
+    pub union_item: u32,
+    pub y: f32,
+}
+
+impl Union {
+    #[doc(alias = "UnionMethodItem")]
+    pub fn method(&self) {}
+}
+
+#[doc(alias = "MacroItem")]
+#[macro_export]
+macro_rules! Macro {
+    () => {}
+}
diff --git a/src/test/rustdoc/intra-link-trait-impl.rs b/src/test/rustdoc/intra-link-trait-impl.rs
new file mode 100644
index 00000000000..fab8406d525
--- /dev/null
+++ b/src/test/rustdoc/intra-link-trait-impl.rs
@@ -0,0 +1,35 @@
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+pub struct MyStruct;
+
+impl MyTrait for MyStruct {
+
+// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: MyStruct::AssoType
+    type AssoType = u32;
+
+// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedconstant.ASSO_CONST'
+
+    /// [`ASSO_CONST`]
+    ///
+    /// [`ASSO_CONST`]: MyStruct::ASSO_CONST
+    const ASSO_CONST: i32 = 10;
+
+// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.trait_fn'
+
+    /// [`trait_fn`]
+    ///
+    /// [`trait_fn`]: MyStruct::trait_fn
+    fn trait_fn() { }
+}
+
+pub trait MyTrait {
+    type AssoType;
+    const ASSO_CONST: i32 = 1;
+    fn trait_fn();
+}
diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs
index 7babfaf6060..11caa34d4b1 100644
--- a/src/test/rustdoc/issue-32374.rs
+++ b/src/test/rustdoc/issue-32374.rs
@@ -10,7 +10,7 @@
 // @matches issue_32374/index.html '//*[@class="docblock-short"]/text()' 'Docs'
 
 // @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
-//      'Deprecated since 1.0.0: text'
+//      '👎 Deprecated since 1.0.0: text'
 // @has - '<code>test</code>&nbsp;<a href="http://issue_url/32374">#32374</a>'
 // @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
 //      '🔬 This is a nightly-only experimental API. \(test\s#32374\)$'
@@ -20,7 +20,7 @@
 pub struct T;
 
 // @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
-//      'Deprecated since 1.0.0: deprecated'
+//      '👎 Deprecated since 1.0.0: deprecated'
 // @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
 //      '🔬 This is a nightly-only experimental API. (test #32374)'
 // @has issue_32374/struct.U.html '//details' \
diff --git a/src/test/rustdoc/test-strikethrough.rs b/src/test/rustdoc/test-strikethrough.rs
new file mode 100644
index 00000000000..c7855729a98
--- /dev/null
+++ b/src/test/rustdoc/test-strikethrough.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - //del "Y"
+/// ~~Y~~
+pub fn f() {}
diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs
index 66b594a1b09..27fe432e96d 100644
--- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs
+++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs
@@ -32,7 +32,6 @@ fn main() {
         TyKind::Never => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Projection(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::UnnormalizedProjection(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Opaque(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Param(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
index ee9f1ff10f8..0486c90a5a0 100644
--- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
+++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
@@ -139,58 +139,52 @@ LL |         TyKind::Projection(..) => (),
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:35:9
    |
-LL |         TyKind::UnnormalizedProjection(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:36:9
-   |
 LL |         TyKind::Opaque(..) => (),
    |         ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:37:9
+  --> $DIR/ty_tykind_usage.rs:36:9
    |
 LL |         TyKind::Param(..) => (),
    |         ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:38:9
+  --> $DIR/ty_tykind_usage.rs:37:9
    |
 LL |         TyKind::Bound(..) => (),
    |         ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:39:9
+  --> $DIR/ty_tykind_usage.rs:38:9
    |
 LL |         TyKind::Placeholder(..) => (),
    |         ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:40:9
+  --> $DIR/ty_tykind_usage.rs:39:9
    |
 LL |         TyKind::Infer(..) => (),
    |         ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:41:9
+  --> $DIR/ty_tykind_usage.rs:40:9
    |
 LL |         TyKind::Error => (),
    |         ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:46:12
+  --> $DIR/ty_tykind_usage.rs:45:12
    |
 LL |     if let TyKind::Int(int_ty) = kind {}
    |            ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:48:24
+  --> $DIR/ty_tykind_usage.rs:47:24
    |
 LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    |                        ^^^^^^^^^^
    |
    = help: try using `Ty` instead
 
-error: aborting due to 31 previous errors
+error: aborting due to 30 previous errors
 
diff --git a/src/test/ui/array-slice-vec/match_arr_unknown_len.rs b/src/test/ui/array-slice-vec/match_arr_unknown_len.rs
index 7f3da75ddcb..45b2889f1ca 100644
--- a/src/test/ui/array-slice-vec/match_arr_unknown_len.rs
+++ b/src/test/ui/array-slice-vec/match_arr_unknown_len.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn is_123<const N: usize>(x: [u32; N]) -> bool {
     match x {
diff --git a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
index 09f65f6acd0..4fe8572c2d5 100644
--- a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
+++ b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/match_arr_unknown_len.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/match_arr_unknown_len.rs:6:9
@@ -13,7 +14,7 @@ LL |         [1, 2] => true,
    |         ^^^^^^ expected `2usize`, found `N`
    |
    = note: expected array `[u32; 2]`
-              found array `[u32; _]`
+              found array `[u32; N]`
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
index f65ae32c01c..cbacc3610dc 100644
--- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
@@ -16,11 +16,13 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterato
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
    |
 LL | fn assume_case1<T: Case1>() {
-   |                    ^^^^^   - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator`
-   |                    |
-   |                    `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
+   |                    ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+help: consider further restricting the associated type
+   |
+LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
@@ -32,11 +34,13 @@ LL |         Send + Iterator<Item:
    |         ---- required by this bound in `Case1`
 ...
 LL | fn assume_case1<T: Case1>() {
-   |                    ^^^^^   - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send`
-   |                    |
-   |                    `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
+   |                    ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+help: consider further restricting the associated type
+   |
+LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
@@ -48,11 +52,13 @@ LL |         > + Sync>;
    |             ---- required by this bound in `Case1`
 ...
 LL | fn assume_case1<T: Case1>() {
-   |                    ^^^^^   - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync`
-   |                    |
-   |                    `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
+   |                    ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+help: consider further restricting the associated type
+   |
+LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs
index f8d230da365..8b396f23efd 100644
--- a/src/test/ui/associated-type-bounds/duplicate.rs
+++ b/src/test/ui/associated-type-bounds/duplicate.rs
@@ -2,7 +2,7 @@
 
 #![feature(associated_type_bounds)]
 #![feature(type_alias_impl_trait)]
-#![feature(impl_trait_in_bindings)] //~ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash [incomplete_features]
+#![feature(impl_trait_in_bindings)] //~ WARN the feature `impl_trait_in_bindings` is incomplete
 #![feature(untagged_unions)]
 
 use std::iter;
diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr
index 9f219fb7c53..71f6e4ff8b6 100644
--- a/src/test/ui/associated-type-bounds/duplicate.stderr
+++ b/src/test/ui/associated-type-bounds/duplicate.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/duplicate.rs:5:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:10:36
diff --git a/src/test/ui/associated-type-bounds/dyn-lcsit.stderr b/src/test/ui/associated-type-bounds/dyn-lcsit.stderr
index 7414c148452..3637f9558be 100644
--- a/src/test/ui/associated-type-bounds/dyn-lcsit.stderr
+++ b/src/test/ui/associated-type-bounds/dyn-lcsit.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/dyn-lcsit.rs:4:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/associated-type-bounds/lcsit.stderr b/src/test/ui/associated-type-bounds/lcsit.stderr
index 8c225a30638..11ff03db361 100644
--- a/src/test/ui/associated-type-bounds/lcsit.stderr
+++ b/src/test/ui/associated-type-bounds/lcsit.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/lcsit.rs:4:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.fixed b/src/test/ui/associated-types/associated-types-bound-failure.fixed
index cc47f31d004..68ee38d16b3 100644
--- a/src/test/ui/associated-types/associated-types-bound-failure.fixed
+++ b/src/test/ui/associated-types/associated-types-bound-failure.fixed
@@ -14,7 +14,7 @@ pub trait GetToInt
 }
 
 fn foo<G>(g: G) -> isize
-    where G : GetToInt, <G as GetToInt>::R: ToInt 
+    where G : GetToInt, <G as GetToInt>::R: ToInt
 {
     ToInt::to_int(&g.get()) //~ ERROR E0277
 }
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr
index c420c86a275..ab8909d1092 100644
--- a/src/test/ui/associated-types/associated-types-bound-failure.stderr
+++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr
@@ -4,11 +4,13 @@ error[E0277]: the trait bound `<G as GetToInt>::R: ToInt` is not satisfied
 LL |     fn to_int(&self) -> isize;
    |     -------------------------- required by `ToInt::to_int`
 ...
-LL |     where G : GetToInt
-   |                       - help: consider further restricting the associated type: `, <G as GetToInt>::R: ToInt`
-LL | {
 LL |     ToInt::to_int(&g.get())
    |                   ^^^^^^^^ the trait `ToInt` is not implemented for `<G as GetToInt>::R`
+   |
+help: consider further restricting the associated type
+   |
+LL |     where G : GetToInt, <G as GetToInt>::R: ToInt
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed
index aa23326506f..80bbef17469 100644
--- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed
+++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed
@@ -7,7 +7,7 @@ trait Get {
 }
 
 trait Other {
-    fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get  {}
+    fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
     //~^ ERROR the trait bound `Self: Get` is not satisfied
 }
 
diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
index 83d5390417e..6d7289bd071 100644
--- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
+++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-for-unimpl-trait.rs:10:5
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
-   |     |                                                       |
-   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
-   |     the trait `Get` is not implemented for `Self`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
+   |                                                              ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
index 6aa0403088d..dfe62aa5d6b 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
-   |     |                                                       |
-   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
-   |     the trait `Get` is not implemented for `Self`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
+   |                                                              ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
index 8c242be9796..f0f2451a1ec 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait.rs:17:5
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
-   |     |                                                       |
-   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
-   |     the trait `Get` is not implemented for `Self`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
+   |                                                              ^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `(T, U): Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait.rs:22:5
diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
index f357045a456..9bc308465eb 100644
--- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
+++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
@@ -7,7 +7,7 @@ trait Get {
 }
 
 trait Other {
-    fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get ;
+    fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get;
     //~^ ERROR E0277
 }
 
diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
index cb01488fa34..4528f03c54a 100644
--- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
+++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
    |
 LL |     fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |                                                       |
-   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
-   |     the trait `Get` is not implemented for `Self`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get;
+   |                                                              ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed
index f780d171fee..9837796e308 100644
--- a/src/test/ui/associated-types/associated-types-unsized.fixed
+++ b/src/test/ui/associated-types/associated-types-unsized.fixed
@@ -6,7 +6,7 @@ trait Get {
     fn get(&self) -> <Self as Get>::Value;
 }
 
-fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized  {
+fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
     let x = t.get(); //~ ERROR the size for values of type
 }
 
diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr
index 2352ac4ad38..6daba54ac69 100644
--- a/src/test/ui/associated-types/associated-types-unsized.stderr
+++ b/src/test/ui/associated-types/associated-types-unsized.stderr
@@ -1,8 +1,6 @@
 error[E0277]: the size for values of type `<T as Get>::Value` cannot be known at compilation time
   --> $DIR/associated-types-unsized.rs:10:9
    |
-LL | fn foo<T:Get>(t: T) {
-   |                    - help: consider further restricting the associated type: `where <T as Get>::Value: std::marker::Sized`
 LL |     let x = t.get();
    |         ^ doesn't have a size known at compile-time
    |
@@ -10,6 +8,10 @@ LL |     let x = t.get();
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider further restricting the associated type
+   |
+LL | fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr
index 3f6702da2a4..8676c1fa223 100644
--- a/src/test/ui/associated-types/defaults-suitability.stderr
+++ b/src/test/ui/associated-types/defaults-suitability.stderr
@@ -85,25 +85,29 @@ error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not
   --> $DIR/defaults-suitability.rs:72:15
    |
 LL | trait Foo2<T> {
-   | -------------- help: consider further restricting the associated type: `where <Self as Foo2<T>>::Baz: std::clone::Clone`
-   | |
-   | required by `Foo2`
+   | ------------- required by `Foo2`
 LL |     type Bar: Clone = Vec<Self::Baz>;
    |               ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo2<T>>::Baz`
    |
    = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo2<T>>::Baz>`
+help: consider further restricting the associated type
+   |
+LL | trait Foo2<T> where <Self as Foo2<T>>::Baz: std::clone::Clone {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: std::clone::Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:81:15
    |
 LL | trait Foo25<T: Clone> {
-   | ---------------------- help: consider further restricting the associated type: `where <Self as Foo25<T>>::Baz: std::clone::Clone`
-   | |
-   | required by `Foo25`
+   | --------------------- required by `Foo25`
 LL |     type Bar: Clone = Vec<Self::Baz>;
    |               ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo25<T>>::Baz`
    |
    = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo25<T>>::Baz>`
+help: consider further restricting the associated type
+   |
+LL | trait Foo25<T: Clone> where <Self as Foo25<T>>::Baz: std::clone::Clone {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:90:16
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
index 856d513d60b..69c310766c1 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
@@ -6,6 +6,11 @@ LL | trait UncheckedCopy: Sized {
 ...
 LL |     type Output: Copy
    |                  ^^^^ the trait `std::marker::Copy` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::marker::Copy {
+   |                            ^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: cannot add-assign `&'static str` to `Self`
   --> $DIR/defaults-unsound-62211-1.rs:25:7
@@ -17,6 +22,10 @@ LL |     + AddAssign<&'static str>
    |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
    |
    = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied
   --> $DIR/defaults-unsound-62211-1.rs:23:7
@@ -26,6 +35,11 @@ LL | trait UncheckedCopy: Sized {
 ...
 LL |     + Deref<Target = str>
    |       ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::ops::Deref {
+   |                            ^^^^^^^^^^^^^^^^^
 
 error[E0277]: `Self` doesn't implement `std::fmt::Display`
   --> $DIR/defaults-unsound-62211-1.rs:28:7
@@ -38,6 +52,10 @@ LL |     + Display = Self;
    |
    = help: the trait `std::fmt::Display` is not implemented for `Self`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::fmt::Display {
+   |                            ^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `T` doesn't implement `std::fmt::Display`
   --> $DIR/defaults-unsound-62211-1.rs:41:9
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
index 1060c82fec2..84f0ba7529e 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
@@ -6,6 +6,11 @@ LL | trait UncheckedCopy: Sized {
 ...
 LL |     type Output: Copy
    |                  ^^^^ the trait `std::marker::Copy` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::marker::Copy {
+   |                            ^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: cannot add-assign `&'static str` to `Self`
   --> $DIR/defaults-unsound-62211-2.rs:25:7
@@ -17,6 +22,10 @@ LL |     + AddAssign<&'static str>
    |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
    |
    = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied
   --> $DIR/defaults-unsound-62211-2.rs:23:7
@@ -26,6 +35,11 @@ LL | trait UncheckedCopy: Sized {
 ...
 LL |     + Deref<Target = str>
    |       ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::ops::Deref {
+   |                            ^^^^^^^^^^^^^^^^^
 
 error[E0277]: `Self` doesn't implement `std::fmt::Display`
   --> $DIR/defaults-unsound-62211-2.rs:28:7
@@ -38,6 +52,10 @@ LL |     + Display = Self;
    |
    = help: the trait `std::fmt::Display` is not implemented for `Self`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+help: consider further restricting `Self`
+   |
+LL | trait UncheckedCopy: Sized + std::fmt::Display {
+   |                            ^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `T` doesn't implement `std::fmt::Display`
   --> $DIR/defaults-unsound-62211-2.rs:41:9
diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr
index c27800f5a3f..82e76ff0b7c 100644
--- a/src/test/ui/associated-types/issue-63593.stderr
+++ b/src/test/ui/associated-types/issue-63593.stderr
@@ -8,6 +8,10 @@ LL |     type This = Self;
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+   |
+LL | trait MyTrait: std::marker::Sized {
+   |              ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs
new file mode 100644
index 00000000000..0474bf0a339
--- /dev/null
+++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs
@@ -0,0 +1,11 @@
+use std::ops::{Add, Sub, Mul, Div};
+
+trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> {}
+//~^ ERROR the size for values of type `Self` cannot be known at compilation time
+
+impl<T> ArithmeticOps for T where T: Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Div<Output=T> {
+    // Nothing to implement, since T already supports the other traits.
+    // It has the functions it needs already
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
new file mode 100644
index 00000000000..a37573dffff
--- /dev/null
+++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/trait-with-supertraits-needing-sized-self.rs:3:22
+   |
+LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> {}
+   |                      ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   | 
+  ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL
+   |
+LL | pub trait Add<Rhs = Self> {
+   |               --- required by this bound in `std::ops::Add`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+   |
+LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + std::marker::Sized {}
+   |                                                                                                ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
index 61f2570b2ff..96158fc0e04 100644
--- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
+++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
@@ -237,7 +237,10 @@ error[E0277]: the `?` operator can only be applied to values that implement `std
   --> $DIR/incorrect-syntax-suggestions.rs:16:19
    |
 LL |     let _ = await bar()?;
-   |                   ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future`
+   |                   ^^^^^^
+   |                   |
+   |                   the `?` operator cannot be applied to type `impl std::future::Future`
+   |                   help: consider using `.await` here: `bar().await?`
    |
    = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
    = note: required by `std::ops::Try::into_result`
diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs
new file mode 100644
index 00000000000..13b45df64ea
--- /dev/null
+++ b/src/test/ui/async-await/issue-61076.rs
@@ -0,0 +1,32 @@
+// edition:2018
+
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+struct T;
+
+impl Future for T {
+    type Output = Result<(), ()>;
+
+    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
+        Poll::Pending
+    }
+}
+
+async fn foo() -> Result<(), ()> {
+    Ok(())
+}
+
+async fn bar() -> Result<(), ()> {
+    foo()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+    Ok(())
+}
+
+async fn baz() -> Result<(), ()> {
+    let t = T;
+    t?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+    Ok(())
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
new file mode 100644
index 00000000000..e71f4e7136d
--- /dev/null
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+  --> $DIR/issue-61076.rs:22:5
+   |
+LL |     foo()?;
+   |     ^^^^^^
+   |     |
+   |     the `?` operator cannot be applied to type `impl std::future::Future`
+   |     help: consider using `.await` here: `foo().await?`
+   |
+   = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
+   = note: required by `std::ops::Try::into_result`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+  --> $DIR/issue-61076.rs:28:5
+   |
+LL |     t?;
+   |     ^^
+   |     |
+   |     the `?` operator cannot be applied to type `T`
+   |     help: consider using `.await` here: `t.await?`
+   |
+   = help: the trait `std::ops::Try` is not implemented for `T`
+   = note: required by `std::ops::Try::into_result`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr
index fe05754c83f..f57e097c125 100644
--- a/src/test/ui/async-await/issue-61949-self-return-type.stderr
+++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr
@@ -6,4 +6,4 @@ LL |     pub async fn new(_bar: &'a i32) -> Self {
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0754`.
+For more information about this error, try `rustc --explain E0755`.
diff --git a/src/test/ui/async-await/try-on-option-in-async.rs b/src/test/ui/async-await/try-on-option-in-async.rs
index 51ac522017c..c520a07abc1 100644
--- a/src/test/ui/async-await/try-on-option-in-async.rs
+++ b/src/test/ui/async-await/try-on-option-in-async.rs
@@ -7,7 +7,8 @@ async fn an_async_block() -> u32 {
         let x: Option<u32> = None;
         x?; //~ ERROR the `?` operator
         22
-    }.await
+    }
+    .await
 }
 
 async fn async_closure_containing_fn() -> u32 {
diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr
index 46f8f41076b..700296d6747 100644
--- a/src/test/ui/async-await/try-on-option-in-async.stderr
+++ b/src/test/ui/async-await/try-on-option-in-async.stderr
@@ -7,14 +7,14 @@ LL | |         let x: Option<u32> = None;
 LL | |         x?;
    | |         ^^ cannot use the `?` operator in an async block that returns `{integer}`
 LL | |         22
-LL | |     }.await
+LL | |     }
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
    = help: the trait `std::ops::Try` is not implemented for `{integer}`
    = note: required by `std::ops::Try::from_error`
 
 error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
-  --> $DIR/try-on-option-in-async.rs:16:9
+  --> $DIR/try-on-option-in-async.rs:17:9
    |
 LL |       let async_closure = async || {
    |  __________________________________-
@@ -29,7 +29,7 @@ LL | |     };
    = note: required by `std::ops::Try::from_error`
 
 error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
-  --> $DIR/try-on-option-in-async.rs:25:5
+  --> $DIR/try-on-option-in-async.rs:26:5
    |
 LL |   async fn an_async_function() -> u32 {
    |  _____________________________________-
diff --git a/src/test/ui/binding/const-param.stderr b/src/test/ui/binding/const-param.stderr
index f6a80c3c7d3..316fac62325 100644
--- a/src/test/ui/binding/const-param.stderr
+++ b/src/test/ui/binding/const-param.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/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
 
 error[E0158]: const parameters cannot be referenced in patterns
   --> $DIR/const-param.rs:7:9
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 7acc50819a6..f9c6e201b17 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,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index b6b83b78d3b..4389e4738ea 100644
--- a/src/test/ui/const-generics/apit-with-const-param.stderr
+++ b/src/test/ui/const-generics/apit-with-const-param.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 3446600d049..6110d16c070 100644
--- a/src/test/ui/const-generics/argument_order.rs
+++ b/src/test/ui/const-generics/argument_order.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct Bad<const N: usize, T> { //~ ERROR type parameters must be declared prior
     arr: [u8; { N }],
diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr
index 7c55cb59a22..f77ae49cf10 100644
--- a/src/test/ui/const-generics/argument_order.stderr
+++ b/src/test/ui/const-generics/argument_order.stderr
@@ -4,13 +4,14 @@ error: type parameters must be declared prior to const parameters
 LL | struct Bad<const N: usize, T> {
    |           -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr
index d795840551c..bd26c08a8e5 100644
--- a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr
+++ b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr
@@ -29,7 +29,7 @@ LL |     let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::boxed::Box<[i32]>>` is not implemented for `std::boxed::Box<[i32; 33]>`
    |
    = help: the following implementations were found:
-             <std::boxed::Box<[T; _]> as std::convert::TryFrom<std::boxed::Box<[T]>>>
+             <std::boxed::Box<[T; N]> as std::convert::TryFrom<std::boxed::Box<[T]>>>
 
 error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From<std::rc::Rc<[i32]>>` is not satisfied
   --> $DIR/alloc-types-no-impls-length-33.rs:19:23
@@ -53,7 +53,7 @@ LL |     let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::rc::Rc<[i32]>>` is not implemented for `std::rc::Rc<[i32; 33]>`
    |
    = help: the following implementations were found:
-             <std::rc::Rc<[T; _]> as std::convert::TryFrom<std::rc::Rc<[T]>>>
+             <std::rc::Rc<[T; N]> as std::convert::TryFrom<std::rc::Rc<[T]>>>
 
 error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From<std::sync::Arc<[i32]>>` is not satisfied
   --> $DIR/alloc-types-no-impls-length-33.rs:26:23
@@ -77,7 +77,7 @@ LL |     let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::sync::Arc<[i32]>>` is not implemented for `std::sync::Arc<[i32; 33]>`
    |
    = help: the following implementations were found:
-             <std::sync::Arc<[T; _]> as std::convert::TryFrom<std::sync::Arc<[T]>>>
+             <std::sync::Arc<[T; N]> as std::convert::TryFrom<std::sync::Arc<[T]>>>
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
index c03377d74e9..76ccc48c32a 100644
--- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
+++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
@@ -39,9 +39,9 @@ LL |     for _ in &[0_usize; 33] {
    |              ^^^^^^^^^^^^^^ the trait `std::iter::IntoIterator` is not implemented for `&[usize; 33]`
    |
    = help: the following implementations were found:
-             <&'a [T; _] as std::iter::IntoIterator>
+             <&'a [T; N] as std::iter::IntoIterator>
              <&'a [T] as std::iter::IntoIterator>
-             <&'a mut [T; _] as std::iter::IntoIterator>
+             <&'a mut [T; N] as std::iter::IntoIterator>
              <&'a mut [T] as std::iter::IntoIterator>
    = note: required by `std::iter::IntoIterator::into_iter`
 
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 d996bf56fcc..5c02e585dc8 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,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #[allow(dead_code)]
 struct ArithArrayLen<const N: usize>([u32; 0 + N]);
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
index 05f30a1cc5e..14cf64eeb7a 100644
--- 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
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
index 2d1a405ebdd..49fc53b32bd 100644
--- a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
+++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #![allow(dead_code)]
 
diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr
index e28f65a3827..e6eb2a0a783 100644
--- a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr
+++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/array-wrapper-struct-ctor.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-1.rs b/src/test/ui/const-generics/broken-mir-1.rs
index 9a11bd3d031..f137be2d6a6 100644
--- a/src/test/ui/const-generics/broken-mir-1.rs
+++ b/src/test/ui/const-generics/broken-mir-1.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 8b8e0fd1120..a5532bde1f5 100644
--- a/src/test/ui/const-generics/broken-mir-1.stderr
+++ b/src/test/ui/const-generics/broken-mir-1.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 d9a4411b4f9..c2f9b786f8f 100644
--- a/src/test/ui/const-generics/broken-mir-2.rs
+++ b/src/test/ui/const-generics/broken-mir-2.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index cbb8159e9b5..05552027f13 100644
--- a/src/test/ui/const-generics/broken-mir-2.stderr
+++ b/src/test/ui/const-generics/broken-mir-2.stderr
@@ -1,19 +1,20 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/broken-mir-2.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[E0277]: arrays only have std trait implementations for lengths 0..=32
   --> $DIR/broken-mir-2.rs:7:36
    |
 LL | struct S<T: Debug, const N: usize>([T; N]);
-   |                                    ^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[T; _]`
+   |                                    ^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[T; N]`
    |
-   = note: required because of the requirements on the impl of `std::fmt::Debug` for `[T; _]`
-   = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[T; _]`
+   = note: required because of the requirements on the impl of `std::fmt::Debug` for `[T; N]`
+   = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[T; N]`
    = note: required for the cast to the object type `dyn std::fmt::Debug`
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
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 e1061c6d1a3..2f6ad2654c1 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,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index fc426bf4f48..6696b025855 100644
--- a/src/test/ui/const-generics/cannot-infer-const-args.stderr
+++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs
index 303bc8326fd..aac5d195f76 100644
--- a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs
+++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs
@@ -1,6 +1,6 @@
 // check-pass
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 // This test confirms that the types can be inferred correctly for this example with const
 // generics. Previously this would ICE, and more recently error.
diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr
index f273c4e9335..c5c48d7be46 100644
--- a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr
+++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/cannot-infer-type-for-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/concrete-const-as-fn-arg.rs b/src/test/ui/const-generics/concrete-const-as-fn-arg.rs
index 54981b77a2b..18ebba49f6f 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
@@ -2,7 +2,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index e83ccf9adb7..c8f3a8beaf8 100644
--- a/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr
+++ b/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 226ea415180..c1ddf9a3314 100644
--- a/src/test/ui/const-generics/concrete-const-impl-method.rs
+++ b/src/test/ui/const-generics/concrete-const-impl-method.rs
@@ -3,7 +3,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index c9145837ea4..5edb4f4f6cd 100644
--- a/src/test/ui/const-generics/concrete-const-impl-method.stderr
+++ b/src/test/ui/const-generics/concrete-const-impl-method.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 091fe904826..9d8aaed54bd 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 12a51d05f46..9ac33454128 100644
--- a/src/test/ui/const-generics/condition-in-trait-const-arg.stderr
+++ b/src/test/ui/const-generics/condition-in-trait-const-arg.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 3f86782838c..5ea2cf92fdc 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 74919ba0ae7..bb66849c7fe 100644
--- a/src/test/ui/const-generics/const-arg-in-fn.stderr
+++ b/src/test/ui/const-generics/const-arg-in-fn.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 f024eb6a957..9f989ee20a5 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 and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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 5795a492c22..ad38b632b75 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,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs
index 22c6c351622..e0b66a7c14c 100644
--- a/src/test/ui/const-generics/const-expression-parameter.rs
+++ b/src/test/ui/const-generics/const-expression-parameter.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 6784aeebf0f..e421c22be01 100644
--- a/src/test/ui/const-generics/const-expression-parameter.stderr
+++ b/src/test/ui/const-generics/const-expression-parameter.stderr
@@ -4,13 +4,14 @@ error: expected one of `,` or `>`, found `+`
 LL |     i32_identity::<1 + 2>();
    |                      ^ expected one of `,` or `>`
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 3d8b77bcf7b..bbc55815e9a 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,6 @@
 // run-pass
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 64b9c18a8f5..109b5002848 100644
--- a/src/test/ui/const-generics/const-fn-with-const-param.stderr
+++ b/src/test/ui/const-generics/const-fn-with-const-param.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 56a58c582f6..3e43387163b 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 1d05381b59b..47448bbd19d 100644
--- a/src/test/ui/const-generics/const-generic-array-wrapper.stderr
+++ b/src/test/ui/const-generics/const-generic-array-wrapper.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 469843d6aae..22f9bd2a0f0 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #[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
index 641b868dcb2..f161739c9c8 100644
--- a/src/test/ui/const-generics/const-generic-type_name.stderr
+++ b/src/test/ui/const-generics/const-generic-type_name.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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-elided-lifetime.rs b/src/test/ui/const-generics/const-param-elided-lifetime.rs
index 5679dd35c30..5e6b6c4dabe 100644
--- a/src/test/ui/const-generics/const-param-elided-lifetime.rs
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.rs
@@ -4,7 +4,7 @@
 // lifetimes within const/static items.
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct A<const N: &u8>;
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.stderr b/src/test/ui/const-generics/const-param-elided-lifetime.stderr
index edc26d6348c..8c50fb73679 100644
--- a/src/test/ui/const-generics/const-param-elided-lifetime.stderr
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.stderr
@@ -28,13 +28,14 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
 
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 6534bcf5ce6..4b8e2db7233 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,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index a03ba080900..30bd1d72914 100644
--- a/src/test/ui/const-generics/const-param-from-outer-fn.stderr
+++ b/src/test/ui/const-generics/const-param-from-outer-fn.stderr
@@ -8,13 +8,14 @@ LL |     fn bar() -> u32 {
 LL |         X
    |         ^ use of generic parameter from outer function
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
 
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 6e4f65fe6ca..68740725711 100644
--- a/src/test/ui/const-generics/const-param-in-trait.rs
+++ b/src/test/ui/const-generics/const-param-in-trait.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 trait Trait<const T: ()> {}
 
diff --git a/src/test/ui/const-generics/const-param-in-trait.stderr b/src/test/ui/const-generics/const-param-in-trait.stderr
index 6afbce67e33..a2e367b25ad 100644
--- a/src/test/ui/const-generics/const-param-in-trait.stderr
+++ b/src/test/ui/const-generics/const-param-in-trait.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
index 7468020366c..654e36df37e 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,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 // Currently, const parameters cannot depend on type parameters, because there is no way to
 // enforce the structural-match property on an arbitrary type parameter. This restriction
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.stderr
index 9f20b06813e..ed05264161e 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.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
   --> $DIR/const-param-type-depends-on-type-param.rs:9:34
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 164205dd75c..54a33e21812 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,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #![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
index 826dc702c0d..b7febed7bdd 100644
--- a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
diff --git a/src/test/ui/const-generics/const-types.rs b/src/test/ui/const-generics/const-types.rs
index bc5188133d7..bde80f4a1ed 100644
--- a/src/test/ui/const-generics/const-types.rs
+++ b/src/test/ui/const-generics/const-types.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #![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
index 935baf1a63a..4628c900318 100644
--- a/src/test/ui/const-generics/const-types.stderr
+++ b/src/test/ui/const-generics/const-types.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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/derive-debug-array-wrapper.rs b/src/test/ui/const-generics/derive-debug-array-wrapper.rs
index eee634c1564..c6d8b32f276 100644
--- a/src/test/ui/const-generics/derive-debug-array-wrapper.rs
+++ b/src/test/ui/const-generics/derive-debug-array-wrapper.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #[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
index 672586fd3fe..a0abbd16894 100644
--- a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr
+++ b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr
@@ -1,19 +1,20 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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: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[E0277]: arrays only have std trait implementations for lengths 0..=32
   --> $DIR/derive-debug-array-wrapper.rs:6:5
    |
 LL |     a: [u32; N],
-   |     ^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[u32; _]`
+   |     ^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[u32; N]`
    |
-   = note: required because of the requirements on the impl of `std::fmt::Debug` for `[u32; _]`
-   = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u32; _]`
+   = note: required because of the requirements on the impl of `std::fmt::Debug` for `[u32; N]`
+   = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u32; N]`
    = note: required for the cast to the object type `dyn std::fmt::Debug`
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/const-generics/different_byref.rs b/src/test/ui/const-generics/different_byref.rs
index c52a5b8061d..78964eb3dee 100644
--- a/src/test/ui/const-generics/different_byref.rs
+++ b/src/test/ui/const-generics/different_byref.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct Const<const V: [usize; 1]> {}
 
diff --git a/src/test/ui/const-generics/different_byref.stderr b/src/test/ui/const-generics/different_byref.stderr
index 9ea2aace89a..001d9852a69 100644
--- a/src/test/ui/const-generics/different_byref.stderr
+++ b/src/test/ui/const-generics/different_byref.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
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 cd4b19db353..afa577fa67f 100644
--- a/src/test/ui/const-generics/fn-const-param-call.rs
+++ b/src/test/ui/const-generics/fn-const-param-call.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics, const_compare_raw_pointers)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 872ec11ad1b..9c0f7e3ab9b 100644
--- a/src/test/ui/const-generics/fn-const-param-call.stderr
+++ b/src/test/ui/const-generics/fn-const-param-call.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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:3:12
    |
 LL | #![feature(const_generics, const_compare_raw_pointers)]
    |            ^^^^^^^^^^^^^^
    |
    = 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/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs
index dc69fa9eea5..08f6e0db31c 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,5 @@
 #![feature(const_generics, const_compare_raw_pointers)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct Checked<const F: fn(usize) -> bool>;
 
diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr
index 7bfb0873a10..3e07393b9aa 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.stderr
+++ b/src/test/ui/const-generics/fn-const-param-infer.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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, const_compare_raw_pointers)]
    |            ^^^^^^^^^^^^^^
    |
    = 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/fn-const-param-infer.rs:16:31
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 d3d17cca4da..8e16221ed4b 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 5a2ef780e14..52fd0a8fec0 100644
--- a/src/test/ui/const-generics/fn-taking-const-generic-array.stderr
+++ b/src/test/ui/const-generics/fn-taking-const-generic-array.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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.rs b/src/test/ui/const-generics/forbid-non-structural_match-types.rs
index a30cdc3efdf..514e215ba1a 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,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #[derive(PartialEq, Eq)]
 struct A;
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
index 4f343146263..600be64b1e1 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
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 4673c8606c3..41113780de3 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,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 extern "C" {
     fn foo<const X: usize>(); //~ ERROR foreign items may not have const parameters
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.stderr b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
index b8fd9854ff6..ee947943af1 100644
--- a/src/test/ui/const-generics/foreign-item-const-parameter.stderr
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
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 87572e51e81..4c2aee59ffe 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 64dbc210d92..9d68df07ce6 100644
--- a/src/test/ui/const-generics/impl-const-generic-struct.stderr
+++ b/src/test/ui/const-generics/impl-const-generic-struct.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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.rs b/src/test/ui/const-generics/incorrect-number-of-const-args.rs
index 7059e9d8348..cea64654e11 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,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index a2492e27e20..51064d7f90f 100644
--- a/src/test/ui/const-generics/incorrect-number-of-const-args.stderr
+++ b/src/test/ui/const-generics/incorrect-number-of-const-args.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
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 a4e3d3dee4a..7e8152dacc4 100644
--- a/src/test/ui/const-generics/infer_arg_from_pat.rs
+++ b/src/test/ui/const-generics/infer_arg_from_pat.rs
@@ -2,7 +2,7 @@
 //
 // see issue #70529
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 7a6da2582a8..f52e5e49a3b 100644
--- a/src/test/ui/const-generics/infer_arg_from_pat.stderr
+++ b/src/test/ui/const-generics/infer_arg_from_pat.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 70633bbb141..cede9ea045d 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
@@ -2,7 +2,7 @@
 //
 // see issue #70529
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index d698abd2bae..dfadfbb1663 100644
--- a/src/test/ui/const-generics/infer_arr_len_from_pat.stderr
+++ b/src/test/ui/const-generics/infer_arr_len_from_pat.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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 30fbfda112c..952e05bac30 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,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn takes_closure_of_array_3<F>(f: F) where F: Fn([i32; 3]) {
     f([1, 2, 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
index 0924f8da25f..aadd10e5cca 100644
--- 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
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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.rs b/src/test/ui/const-generics/issue-61522-array-len-succ.rs
index 3b627a5e530..7c8cdeece87 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,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
 //~^ ERROR constant expression depends on a generic parameter
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
index d52ae10ee07..a1fbd5f2025 100644
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.stderr
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
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 b677dcc4af4..74f036e6d89 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,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 trait Trait<const NAME: &'static str> {
     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
index edaa59bbdc7..720420d9cd6 100644
--- 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
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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/issues/issue-60818-struct-constructors.rs b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs
index fb234eb0827..26d74ffb254 100644
--- a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs
+++ b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct Generic<const V: usize>;
 
diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr
index 887d4547933..94a2b673a51 100644
--- a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr
+++ b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-60818-struct-constructors.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/issues/issue-61336-1.rs b/src/test/ui/const-generics/issues/issue-61336-1.rs
index 165d3e1c2e6..2135c868bbc 100644
--- a/src/test/ui/const-generics/issues/issue-61336-1.rs
+++ b/src/test/ui/const-generics/issues/issue-61336-1.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 // build-pass
 
diff --git a/src/test/ui/const-generics/issues/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr
index 34920d8907f..b2c69d57c40 100644
--- a/src/test/ui/const-generics/issues/issue-61336-1.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-1.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-61336-1.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
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs
index c5bf6b6ce94..52969056f00 100644
--- a/src/test/ui/const-generics/issues/issue-61336-2.rs
+++ b/src/test/ui/const-generics/issues/issue-61336-2.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; { N }]
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr
index 27ee4f88870..5f3395223f9 100644
--- a/src/test/ui/const-generics/issues/issue-61336-2.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-61336-2.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[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/issue-61336-2.rs:9:5
diff --git a/src/test/ui/const-generics/issues/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs
index 7e84e62d8be..eb0f3097627 100644
--- a/src/test/ui/const-generics/issues/issue-61336.rs
+++ b/src/test/ui/const-generics/issues/issue-61336.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr
index 772a07cccf8..0eee37df3dd 100644
--- a/src/test/ui/const-generics/issues/issue-61336.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-61336.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[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/issue-61336.rs:9:5
diff --git a/src/test/ui/const-generics/issues/issue-61422.rs b/src/test/ui/const-generics/issues/issue-61422.rs
index 4fa150ffef0..7e7ef6867ed 100644
--- a/src/test/ui/const-generics/issues/issue-61422.rs
+++ b/src/test/ui/const-generics/issues/issue-61422.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 use std::mem;
 
diff --git a/src/test/ui/const-generics/issues/issue-61422.stderr b/src/test/ui/const-generics/issues/issue-61422.stderr
index a66224b6d17..69bbaada691 100644
--- a/src/test/ui/const-generics/issues/issue-61422.stderr
+++ b/src/test/ui/const-generics/issues/issue-61422.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-61422.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/issues/issue-61432.rs b/src/test/ui/const-generics/issues/issue-61432.rs
index 832095ce542..0440468e9e6 100644
--- a/src/test/ui/const-generics/issues/issue-61432.rs
+++ b/src/test/ui/const-generics/issues/issue-61432.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn promote<const N: i32>() {
     // works:
diff --git a/src/test/ui/const-generics/issues/issue-61432.stderr b/src/test/ui/const-generics/issues/issue-61432.stderr
index cb2fa99f6d8..1d547b1b6c9 100644
--- a/src/test/ui/const-generics/issues/issue-61432.stderr
+++ b/src/test/ui/const-generics/issues/issue-61432.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-61432.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/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs
index 64674bb894e..9e0572d3568 100644
--- a/src/test/ui/const-generics/issues/issue-61747.rs
+++ b/src/test/ui/const-generics/issues/issue-61747.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct Const<const N: usize>;
 
diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr
index 3465db15208..2e405370dc0 100644
--- a/src/test/ui/const-generics/issues/issue-61747.stderr
+++ b/src/test/ui/const-generics/issues/issue-61747.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-61747.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/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs
index 4e5e4d045c8..2f3b5c5dc5b 100644
--- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs
+++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 pub trait BitLen: Sized {
     const BIT_LEN: usize;
diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr
index 70d0b61cc26..a9abb877c09 100644
--- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr
+++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-62187-encountered-polymorphic-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: unused variable: `foo`
   --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9
diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs
index 5d068eb7fc8..37947ad1b33 100644
--- a/src/test/ui/const-generics/issues/issue-62456.rs
+++ b/src/test/ui/const-generics/issues/issue-62456.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn foo<const N: usize>() {
     let _ = [0u64; N + 1];
diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr
index 96a07110e73..0454fed6705 100644
--- a/src/test/ui/const-generics/issues/issue-62456.stderr
+++ b/src/test/ui/const-generics/issues/issue-62456.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-62456.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-62456.rs:5:20
diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.stderr
index a3a864f770c..5d45e302888 100644
--- a/src/test/ui/const-generics/issues/issue-62504.stderr
+++ b/src/test/ui/const-generics/issues/issue-62504.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |         ArrayHolder([0; Self::SIZE])
    |                     ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
    |
-   = note: expected array `[u32; _]`
+   = note: expected array `[u32; X]`
               found array `[u32; _]`
 
 error: constant expression depends on a generic parameter
diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.rs b/src/test/ui/const-generics/issues/issue-62579-no-match.rs
index 0ff7ddc41fe..7eaf5eea078 100644
--- a/src/test/ui/const-generics/issues/issue-62579-no-match.rs
+++ b/src/test/ui/const-generics/issues/issue-62579-no-match.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 #[derive(PartialEq, Eq)]
 struct NoMatch;
diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.stderr
index 31f8d230935..9fb9b5b13d8 100644
--- a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr
+++ b/src/test/ui/const-generics/issues/issue-62579-no-match.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-62579-no-match.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/issues/issue-63322-forbid-dyn.rs b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
index 2bacd6c9a9c..2bcaa27b4d2 100644
--- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
+++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 trait A {}
 struct B;
diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr
index c3db6c65a8f..32054e43716 100644
--- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr
+++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-63322-forbid-dyn.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]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
   --> $DIR/issue-63322-forbid-dyn.rs:8:18
diff --git a/src/test/ui/const-generics/issues/issue-64519.rs b/src/test/ui/const-generics/issues/issue-64519.rs
index 72cce9b4843..e9391096b04 100644
--- a/src/test/ui/const-generics/issues/issue-64519.rs
+++ b/src/test/ui/const-generics/issues/issue-64519.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct Foo<const D: usize> {
     state: Option<[u8; D]>,
diff --git a/src/test/ui/const-generics/issues/issue-64519.stderr b/src/test/ui/const-generics/issues/issue-64519.stderr
index 94c010ba260..6552aea4ad1 100644
--- a/src/test/ui/const-generics/issues/issue-64519.stderr
+++ b/src/test/ui/const-generics/issues/issue-64519.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-64519.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/issues/issue-66906.rs b/src/test/ui/const-generics/issues/issue-66906.rs
index 461fe837dac..486c72d8a34 100644
--- a/src/test/ui/const-generics/issues/issue-66906.rs
+++ b/src/test/ui/const-generics/issues/issue-66906.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 pub struct Tuple;
 
diff --git a/src/test/ui/const-generics/issues/issue-66906.stderr b/src/test/ui/const-generics/issues/issue-66906.stderr
index 6730c97604c..8e8b552f90e 100644
--- a/src/test/ui/const-generics/issues/issue-66906.stderr
+++ b/src/test/ui/const-generics/issues/issue-66906.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-66906.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/issues/issue-70125-1.rs b/src/test/ui/const-generics/issues/issue-70125-1.rs
index 8b933c078ff..08a8309d431 100644
--- a/src/test/ui/const-generics/issues/issue-70125-1.rs
+++ b/src/test/ui/const-generics/issues/issue-70125-1.rs
@@ -1,6 +1,6 @@
 // run-pass
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 const L: usize = 4;
 
diff --git a/src/test/ui/const-generics/issues/issue-70125-1.stderr b/src/test/ui/const-generics/issues/issue-70125-1.stderr
index b095d577fb7..8ad4b25ae5b 100644
--- a/src/test/ui/const-generics/issues/issue-70125-1.stderr
+++ b/src/test/ui/const-generics/issues/issue-70125-1.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-70125-1.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/issues/issue-70125-2.rs b/src/test/ui/const-generics/issues/issue-70125-2.rs
index a3eca0dd7d9..fb7d4886a7c 100644
--- a/src/test/ui/const-generics/issues/issue-70125-2.rs
+++ b/src/test/ui/const-generics/issues/issue-70125-2.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn main() {
     <()>::foo();
diff --git a/src/test/ui/const-generics/issues/issue-70125-2.stderr b/src/test/ui/const-generics/issues/issue-70125-2.stderr
index 6a30e5e783e..c1f9634810e 100644
--- a/src/test/ui/const-generics/issues/issue-70125-2.stderr
+++ b/src/test/ui/const-generics/issues/issue-70125-2.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-70125-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/issues/issue-70167.rs b/src/test/ui/const-generics/issues/issue-70167.rs
index 58fac8e0511..b53cec80071 100644
--- a/src/test/ui/const-generics/issues/issue-70167.rs
+++ b/src/test/ui/const-generics/issues/issue-70167.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 pub trait Trait<const N: usize>: From<<Self as Trait<N>>::Item> {
   type Item;
diff --git a/src/test/ui/const-generics/issues/issue-70167.stderr b/src/test/ui/const-generics/issues/issue-70167.stderr
index 2b56ed977ee..5d647e933c4 100644
--- a/src/test/ui/const-generics/issues/issue-70167.stderr
+++ b/src/test/ui/const-generics/issues/issue-70167.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-70167.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/issues/issue70273-assoc-fn.rs b/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs
index a192ddea9c6..c22e61d0ce3 100644
--- a/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs
+++ b/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 trait T<const A: usize> {
     fn f();
diff --git a/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr b/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr
index afd2a50242f..931701b64b4 100644
--- a/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr
+++ b/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue70273-assoc-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/mut-ref-const-param-array.rs b/src/test/ui/const-generics/mut-ref-const-param-array.rs
index f930fb87963..9ca1f4552f5 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ 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
index 336364e5aea..acbc2df1d74 100644
--- a/src/test/ui/const-generics/mut-ref-const-param-array.stderr
+++ b/src/test/ui/const-generics/mut-ref-const-param-array.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
index 745dde3c287..c498bfe2e97 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,6 +1,6 @@
 // run-pass
 #![feature(const_generics, const_compare_raw_pointers)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 736c9b49725..1ffc63ffdac 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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:2:12
    |
 LL | #![feature(const_generics, const_compare_raw_pointers)]
    |            ^^^^^^^^^^^^^^
    |
    = 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/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs
index f0349f46962..d7d970e952b 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,5 @@
 #![feature(const_generics, const_compare_raw_pointers)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct Const<const P: *const u32>;
 
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr
index a2496a6558d..6644c72236b 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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, const_compare_raw_pointers)]
    |            ^^^^^^^^^^^^^^
    |
    = 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/raw-ptr-const-param.rs:7:40
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 73c75ae6668..4f321b02b82 100644
--- a/src/test/ui/const-generics/slice-const-param-mismatch.rs
+++ b/src/test/ui/const-generics/slice-const-param-mismatch.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct ConstString<const T: &'static str>;
 struct ConstBytes<const T: &'static [u8]>;
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.stderr
index e497cc3220d..cc21f197e08 100644
--- a/src/test/ui/const-generics/slice-const-param-mismatch.stderr
+++ b/src/test/ui/const-generics/slice-const-param-mismatch.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
diff --git a/src/test/ui/const-generics/slice-const-param.rs b/src/test/ui/const-generics/slice-const-param.rs
index 2629caa3921..9668f7ddabb 100644
--- a/src/test/ui/const-generics/slice-const-param.rs
+++ b/src/test/ui/const-generics/slice-const-param.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 pub fn function_with_str<const STRING: &'static str>() -> &'static str {
     STRING
diff --git a/src/test/ui/const-generics/slice-const-param.stderr b/src/test/ui/const-generics/slice-const-param.stderr
index 80fdf3296bc..524bd41a669 100644
--- a/src/test/ui/const-generics/slice-const-param.stderr
+++ b/src/test/ui/const-generics/slice-const-param.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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.rs b/src/test/ui/const-generics/struct-with-invalid-const-param.rs
index 207b07bf695..0b00481d903 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,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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 7472793f809..a968b26bc26 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
@@ -7,13 +7,14 @@ LL | struct S<const C: u8>(C);
    | |                     help: a struct with a similar name exists: `S`
    | similarly named struct `S` defined here
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
    |
 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/transparent-maybeunit-array-wrapper.rs b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs
index 794048174f9..1aed9cfe927 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 0bf40839813..6077fe5b1ed 100644
--- a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr
+++ b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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_of_anon_const.rs b/src/test/ui/const-generics/type_of_anon_const.rs
index 776084b77a5..588c7b9523a 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,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 5f848c3ec52..8afed0d3986 100644
--- a/src/test/ui/const-generics/type_of_anon_const.stderr
+++ b/src/test/ui/const-generics/type_of_anon_const.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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/types-mismatch-const-args.rs b/src/test/ui/const-generics/types-mismatch-const-args.rs
index b25b7331017..bf517c11262 100644
--- a/src/test/ui/const-generics/types-mismatch-const-args.rs
+++ b/src/test/ui/const-generics/types-mismatch-const-args.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 // tests the diagnostic output of type mismatches for types that have const generics arguments.
 
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.stderr b/src/test/ui/const-generics/types-mismatch-const-args.stderr
index a76bbd177fb..2131738554f 100644
--- a/src/test/ui/const-generics/types-mismatch-const-args.stderr
+++ b/src/test/ui/const-generics/types-mismatch-const-args.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/types-mismatch-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[E0308]: mismatched types
   --> $DIR/types-mismatch-const-args.rs:13:41
diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs
index 7942631bb70..7473718351e 100644
--- a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs
+++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 use std::fmt;
 
diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr
index c1d115b4f1d..f41628d5d8e 100644
--- a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr
+++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/uninferred-consts-during-codegen-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/uninferred-consts-during-codegen-2.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs
index 0cf505906f6..8b95a010473 100644
--- a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs
+++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 use std::fmt;
 
diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr
index 2738f37b21e..f1703bc3a2f 100644
--- a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr
+++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/uninferred-consts-during-codegen-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/unused-const-param.rs b/src/test/ui/const-generics/unused-const-param.rs
index 8025b3af8f1..d9292efc21b 100644
--- a/src/test/ui/const-generics/unused-const-param.rs
+++ b/src/test/ui/const-generics/unused-const-param.rs
@@ -1,7 +1,7 @@
 // check-pass
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 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
index 6d3d1a612b8..be015a689ae 100644
--- a/src/test/ui/const-generics/unused-const-param.stderr
+++ b/src/test/ui/const-generics/unused-const-param.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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.rs b/src/test/ui/const-generics/unused_braces.rs
index 05234faf714..2c3ce7c9eab 100644
--- a/src/test/ui/const-generics/unused_braces.rs
+++ b/src/test/ui/const-generics/unused_braces.rs
@@ -2,7 +2,7 @@
 #![warn(unused_braces)]
 
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 struct A<const N: usize>;
 
diff --git a/src/test/ui/const-generics/unused_braces.stderr b/src/test/ui/const-generics/unused_braces.stderr
index 2cc4070f76e..e14958ee566 100644
--- a/src/test/ui/const-generics/unused_braces.stderr
+++ b/src/test/ui/const-generics/unused_braces.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/unused_braces.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: unnecessary braces around const expression
   --> $DIR/unused_braces.rs:11:14
diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr
index 649105812b0..d24491e1bc5 100644
--- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr
+++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/const-pointer-values-in-various-types.rs:25:5
    |
 LL |     const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc2+0x0, but expected initialized plain (non-pointer) bytes
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc2, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/const-pointer-values-in-various-types.rs:37:5
    |
 LL |     const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22+0x0, but expected initialized plain (non-pointer) bytes
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -76,7 +76,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/const-pointer-values-in-various-types.rs:52:5
    |
 LL |     const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc47+0x0, but expected initialized plain (non-pointer) bytes
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc47, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -100,7 +100,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/const-pointer-values-in-various-types.rs:61:5
    |
 LL |     const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc62+0x0, but expected initialized plain (non-pointer) bytes
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc62, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -148,7 +148,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/const-pointer-values-in-various-types.rs:79:5
    |
 LL |     const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86+0x0, but expected initialized plain (non-pointer) bytes
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -188,7 +188,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/const-pointer-values-in-various-types.rs:94:5
    |
 LL |     const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc101+0x0, but expected initialized plain (non-pointer) bytes
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc101, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -212,7 +212,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/const-pointer-values-in-various-types.rs:103:5
    |
 LL |     const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc110+0x0, but expected initialized plain (non-pointer) bytes
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc110, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.stderr
index df6fc66620b..cb0ba5d9929 100644
--- a/src/test/ui/consts/const-eval/ref_to_int_match.stderr
+++ b/src/test/ui/consts/const-eval/ref_to_int_match.stderr
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ref_to_int_match.rs:25:1
    |
 LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc2+0x0, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc2, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr
index 8f0ce58eaf5..d8dafac3e70 100644
--- a/src/test/ui/consts/const-eval/ub-enum.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.stderr
@@ -10,7 +10,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8+0x0 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc13+0x0 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc13 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:44:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc20+0x0 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc20 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -42,7 +42,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:47:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc25+0x0 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc25 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -58,7 +58,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:60:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc32+0x0 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc32 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr
index 95a83d11acd..a219679f182 100644
--- a/src/test/ui/consts/const-eval/ub-ref.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref.stderr
@@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref.rs:24:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc16+0x0, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc16, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
index 29ac32fcf22..f69f6a1109f 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
@@ -42,11 +42,11 @@ const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
 const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
 //~^ ERROR it is undefined behavior to use this value
 
-// invalid UTF-8
-const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) };
+// uninitialized byte
+const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
 //~^ ERROR it is undefined behavior to use this value
-// invalid UTF-8 in user-defined str-like
-const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) };
+// uninitialized byte in user-defined str-like
+const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
 //~^ ERROR it is undefined behavior to use this value
 
 // # slice
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
index 063ea81036b..47d29ffc9b3 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -41,16 +41,16 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize:
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:46:1
    |
-LL | const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>
+LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:49:1
    |
-LL | const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>.0
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
diff --git a/src/test/ui/consts/dangling-alloc-id-ice.rs b/src/test/ui/consts/dangling-alloc-id-ice.rs
index dbc50f1fbd4..3b7f1de5b9b 100644
--- a/src/test/ui/consts/dangling-alloc-id-ice.rs
+++ b/src/test/ui/consts/dangling-alloc-id-ice.rs
@@ -1,11 +1,13 @@
 // https://github.com/rust-lang/rust/issues/55223
+#![allow(const_err)]
 
 union Foo<'a> {
     y: &'a (),
     long_live_the_unit: &'static (),
 }
 
-const FOO: &() = { //~ ERROR any use of this value will cause an error
+const FOO: &() = { //~ ERROR it is undefined behavior to use this value
+//~^ ERROR encountered dangling pointer in final constant
     let y = ();
     unsafe { Foo { y: &y }.long_live_the_unit }
 };
diff --git a/src/test/ui/consts/dangling-alloc-id-ice.stderr b/src/test/ui/consts/dangling-alloc-id-ice.stderr
index 0e213555052..14a49810b9d 100644
--- a/src/test/ui/consts/dangling-alloc-id-ice.stderr
+++ b/src/test/ui/consts/dangling-alloc-id-ice.stderr
@@ -1,13 +1,25 @@
-error: any use of this value will cause an error
-  --> $DIR/dangling-alloc-id-ice.rs:8:1
+error: encountered dangling pointer in final constant
+  --> $DIR/dangling-alloc-id-ice.rs:9:1
    |
 LL | / const FOO: &() = {
+LL | |
 LL | |     let y = ();
 LL | |     unsafe { Foo { y: &y }.long_live_the_unit }
 LL | | };
-   | |__^ encountered dangling pointer in final constant
+   | |__^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/dangling-alloc-id-ice.rs:9:1
+   |
+LL | / const FOO: &() = {
+LL | |
+LL | |     let y = ();
+LL | |     unsafe { Foo { y: &y }.long_live_the_unit }
+LL | | };
+   | |__^ type validation failed: encountered a dangling reference (use-after-free)
    |
-   = note: `#[deny(const_err)]` on by default
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/dangling_raw_ptr.rs b/src/test/ui/consts/dangling_raw_ptr.rs
index c2d8e6d421a..ddd1fb1ba76 100644
--- a/src/test/ui/consts/dangling_raw_ptr.rs
+++ b/src/test/ui/consts/dangling_raw_ptr.rs
@@ -1,4 +1,4 @@
-const FOO: *const u32 = { //~ ERROR any use of this value will cause an error
+const FOO: *const u32 = { //~ ERROR encountered dangling pointer in final constant
     let x = 42;
     &x
 };
diff --git a/src/test/ui/consts/dangling_raw_ptr.stderr b/src/test/ui/consts/dangling_raw_ptr.stderr
index 4d4c2876c45..a79ac62d5cd 100644
--- a/src/test/ui/consts/dangling_raw_ptr.stderr
+++ b/src/test/ui/consts/dangling_raw_ptr.stderr
@@ -1,13 +1,11 @@
-error: any use of this value will cause an error
+error: encountered dangling pointer in final constant
   --> $DIR/dangling_raw_ptr.rs:1:1
    |
 LL | / const FOO: *const u32 = {
 LL | |     let x = 42;
 LL | |     &x
 LL | | };
-   | |__^ encountered dangling pointer in final constant
-   |
-   = note: `#[deny(const_err)]` on by default
+   | |__^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs
deleted file mode 100644
index f8aa6528273..00000000000
--- a/src/test/ui/consts/miri_unleashed/mutable_const.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// compile-flags: -Zunleash-the-miri-inside-of-you
-// normalize-stderr-test "alloc[0-9]+" -> "allocN"
-
-#![deny(const_err)] // The `allow` variant is tested by `mutable_const2`.
-//~^ NOTE lint level
-// Here we check that even though `MUTABLE_BEHIND_RAW` is created from a mutable
-// allocation, we intern that allocation as *immutable* and reject writes to it.
-// We avoid the `delay_span_bug` ICE by having compilation fail via the `deny` above.
-
-use std::cell::UnsafeCell;
-
-// make sure we do not just intern this as mutable
-const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-
-const MUTATING_BEHIND_RAW: () = { //~ NOTE
-    // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
-    unsafe {
-        *MUTABLE_BEHIND_RAW = 99 //~ ERROR any use of this value will cause an error
-        //~^ NOTE: which is read-only
-        // FIXME would be good to match more of the error message here, but looks like we
-        // normalize *after* checking the annoations here.
-    }
-};
-
-fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr
deleted file mode 100644
index 4772baf9d9a..00000000000
--- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/mutable_const.rs:18:9
-   |
-LL | / const MUTATING_BEHIND_RAW: () = {
-LL | |     // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
-LL | |     unsafe {
-LL | |         *MUTABLE_BEHIND_RAW = 99
-   | |         ^^^^^^^^^^^^^^^^^^^^^^^^ writing to allocN which is read-only
-...  |
-LL | |     }
-LL | | };
-   | |__-
-   |
-note: the lint level is defined here
-  --> $DIR/mutable_const.rs:4:9
-   |
-LL | #![deny(const_err)] // The `allow` variant is tested by `mutable_const2`.
-   |         ^^^^^^^^^
-
-warning: skipping const checks
-   |
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_const.rs:13:38
-   |
-LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-   |                                      ^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_raw_ptr_deref` feature
-  --> $DIR/mutable_const.rs:18:9
-   |
-LL |         *MUTABLE_BEHIND_RAW = 99
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_const.rs:18:9
-   |
-LL |         *MUTABLE_BEHIND_RAW = 99
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const2.rs b/src/test/ui/consts/miri_unleashed/mutable_const2.rs
deleted file mode 100644
index 867091af7ba..00000000000
--- a/src/test/ui/consts/miri_unleashed/mutable_const2.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-// compile-flags: -Zunleash-the-miri-inside-of-you
-// failure-status: 101
-// rustc-env:RUST_BACKTRACE=0
-// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET"
-// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS"
-// normalize-stderr-test "interpret/intern.rs:[0-9]+:[0-9]+" -> "interpret/intern.rs:LL:CC"
-
-#![allow(const_err)]
-
-use std::cell::UnsafeCell;
-
-// make sure we do not just intern this as mutable
-const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-//~^ ERROR: mutable allocation in constant
-
-fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const2.stderr b/src/test/ui/consts/miri_unleashed/mutable_const2.stderr
deleted file mode 100644
index 98a1c8bdd89..00000000000
--- a/src/test/ui/consts/miri_unleashed/mutable_const2.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-warning: skipping const checks
-   |
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_const2.rs:13:38
-   |
-LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-   |                                      ^^^^^^^^^^^^^^^^^^^^
-
-warning: 1 warning emitted
-
-error: internal compiler error: mutable allocation in constant
-  --> $DIR/mutable_const2.rs:13:1
-   |
-LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:366:17
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-
-error: internal compiler error: unexpected panic
-
-note: the compiler unexpectedly panicked. this is a bug.
-
-note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
-
-note: rustc VERSION running on TARGET
-
-note: compiler flags: FLAGS
-
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs
index ed2ca86ba2c..ca927ef4a51 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references.rs
+++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs
@@ -17,12 +17,11 @@ struct Foo<T>(T);
 // this is fine for the same reason as `BAR`.
 static BOO: &mut Foo<()> = &mut Foo(());
 
+// interior mutability is fine
 struct Meh {
     x: &'static UnsafeCell<i32>,
 }
-
 unsafe impl Sync for Meh {}
-
 static MEH: Meh = Meh {
     x: &UnsafeCell::new(42),
 };
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
index 83c4e0ceba0..7109ffd8b61 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item
-  --> $DIR/mutable_references.rs:37:5
+  --> $DIR/mutable_references.rs:36:5
    |
 LL |     *OH_YES = 99;
    |     ^^^^^^^^^^^^ cannot assign
@@ -22,12 +22,12 @@ help: skipping check for `const_mut_refs` feature
 LL | static BOO: &mut Foo<()> = &mut Foo(());
    |                            ^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references.rs:27:8
+  --> $DIR/mutable_references.rs:26:8
    |
 LL |     x: &UnsafeCell::new(42),
    |        ^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references.rs:31:27
+  --> $DIR/mutable_references.rs:30:27
    |
 LL | static OH_YES: &mut i32 = &mut 42;
    |                           ^^^^^^^
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.rs b/src/test/ui/consts/miri_unleashed/mutable_references_err.rs
new file mode 100644
index 00000000000..06fb27bcff8
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.rs
@@ -0,0 +1,37 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+
+#![allow(const_err)]
+
+use std::cell::UnsafeCell;
+
+// this test ensures that our mutability story is sound
+
+struct Meh {
+    x: &'static UnsafeCell<i32>,
+}
+unsafe impl Sync for Meh {}
+
+// the following will never be ok! no interior mut behind consts, because
+// all allocs interned here will be marked immutable.
+const MUH: Meh = Meh { //~ ERROR: mutable memory (`UnsafeCell`) is not allowed in constant
+    x: &UnsafeCell::new(42),
+};
+
+struct Synced {
+    x: UnsafeCell<i32>,
+}
+unsafe impl Sync for Synced {}
+
+// Make sure we also catch this behind a type-erased `dyn Trait` reference.
+const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
+//~^ ERROR: mutable memory (`UnsafeCell`) is not allowed in constant
+
+// Make sure we also catch mutable references.
+const BLUNT: &mut i32 = &mut 42;
+//~^ ERROR: mutable memory (`&mut`) is not allowed in constant
+
+fn main() {
+    unsafe {
+        *MUH.x.get() = 99;
+    }
+}
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr
new file mode 100644
index 00000000000..45e7d5a2cc3
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr
@@ -0,0 +1,40 @@
+error: mutable memory (`UnsafeCell`) is not allowed in constant
+  --> $DIR/mutable_references_err.rs:16:1
+   |
+LL | / const MUH: Meh = Meh {
+LL | |     x: &UnsafeCell::new(42),
+LL | | };
+   | |__^
+
+error: mutable memory (`UnsafeCell`) is not allowed in constant
+  --> $DIR/mutable_references_err.rs:26:1
+   |
+LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mutable memory (`&mut`) is not allowed in constant
+  --> $DIR/mutable_references_err.rs:30:1
+   |
+LL | const BLUNT: &mut i32 = &mut 42;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: skipping const checks
+   |
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references_err.rs:17:8
+   |
+LL |     x: &UnsafeCell::new(42),
+   |        ^^^^^^^^^^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references_err.rs:26:27
+   |
+LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: skipping check for `const_mut_refs` feature
+  --> $DIR/mutable_references_err.rs:30:25
+   |
+LL | const BLUNT: &mut i32 = &mut 42;
+   |                         ^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs b/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs
deleted file mode 100644
index 7388aad2a9e..00000000000
--- a/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// compile-flags: -Zunleash-the-miri-inside-of-you
-// failure-status: 101
-// rustc-env:RUST_BACKTRACE=0
-// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET"
-// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS"
-// normalize-stderr-test "interpret/intern.rs:[0-9]+:[0-9]+" -> "interpret/intern.rs:LL:CC"
-
-#![allow(const_err)]
-
-use std::cell::UnsafeCell;
-
-// this test ICEs to ensure that our mutability story is sound
-
-struct Meh {
-    x: &'static UnsafeCell<i32>,
-}
-
-unsafe impl Sync for Meh {}
-
-// the following will never be ok!
-const MUH: Meh = Meh {
-    x: &UnsafeCell::new(42),
-};
-
-fn main() {
-    unsafe {
-        *MUH.x.get() = 99;
-    }
-}
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr
deleted file mode 100644
index 7ddf77af4d3..00000000000
--- a/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-thread 'rustc' panicked at 'assertion failed: `(left != right)`
-  left: `Const`,
- right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites could observe that mutation.', src/librustc_mir/interpret/intern.rs:LL:CC
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-
-error: internal compiler error: unexpected panic
-
-note: the compiler unexpectedly panicked. this is a bug.
-
-note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
-
-note: rustc VERSION running on TARGET
-
-note: compiler flags: FLAGS
-
-warning: skipping const checks
-   |
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_ice.rs:22:8
-   |
-LL |     x: &UnsafeCell::new(42),
-   |        ^^^^^^^^^^^^^^^^^^^^
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
new file mode 100644
index 00000000000..81985f9f625
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
@@ -0,0 +1,29 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(core_intrinsics)]
+#![allow(const_err)]
+
+// A test demonstrating that we prevent doing even trivial
+// pointer arithmetic or comparison during CTFE.
+
+static CMP: () = {
+    let x = &0 as *const _;
+    let _v = x == x;
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE pointer arithmetic or comparison
+};
+
+static INT_PTR_ARITH: () = unsafe {
+    let x: usize = std::mem::transmute(&0);
+    let _v = x + 0;
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE pointer-to-integer cast
+};
+
+static PTR_ARITH: () = unsafe {
+    let x = &0 as *const _;
+    let _v = core::intrinsics::offset(x, 0);
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE calling intrinsic `offset`
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
new file mode 100644
index 00000000000..5bd534a16b8
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
@@ -0,0 +1,39 @@
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ptr_arith.rs:10:14
+   |
+LL |     let _v = x == x;
+   |              ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ptr_arith.rs:17:14
+   |
+LL |     let _v = x + 0;
+   |              ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ptr_arith.rs:24:14
+   |
+LL |     let _v = core::intrinsics::offset(x, 0);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants
+
+warning: skipping const checks
+   |
+help: skipping check for `const_compare_raw_pointers` feature
+  --> $DIR/ptr_arith.rs:10:14
+   |
+LL |     let _v = x == x;
+   |              ^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/ptr_arith.rs:16:20
+   |
+LL |     let x: usize = std::mem::transmute(&0);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/ptr_arith.rs:24:14
+   |
+LL |     let _v = core::intrinsics::offset(x, 0);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/miri_unleashed/raw_mutable_const.rs b/src/test/ui/consts/miri_unleashed/raw_mutable_const.rs
new file mode 100644
index 00000000000..cabd754e01a
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/raw_mutable_const.rs
@@ -0,0 +1,10 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+
+#![allow(const_err)]
+
+use std::cell::UnsafeCell;
+
+const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+//~^ ERROR: untyped pointers are not allowed in constant
+
+fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr b/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr
new file mode 100644
index 00000000000..b5b5a965295
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr
@@ -0,0 +1,16 @@
+error: untyped pointers are not allowed in constant
+  --> $DIR/raw_mutable_const.rs:7:1
+   |
+LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: skipping const checks
+   |
+help: skipping check that does not even have a feature gate
+  --> $DIR/raw_mutable_const.rs:7:38
+   |
+LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+   |                                      ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/consts/raw-ptr-const.rs b/src/test/ui/consts/raw-ptr-const.rs
new file mode 100644
index 00000000000..00fad046b55
--- /dev/null
+++ b/src/test/ui/consts/raw-ptr-const.rs
@@ -0,0 +1,10 @@
+#![allow(const_err)] // make sure we hit the `delay_span_bug`
+
+// This is a regression test for a `delay_span_bug` during interning when a constant
+// evaluates to a (non-dangling) raw pointer.  For now this errors; potentially it
+// could also be allowed.
+
+const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _;
+//~^ ERROR untyped pointers are not allowed in constant
+
+fn main() {}
diff --git a/src/test/ui/consts/raw-ptr-const.stderr b/src/test/ui/consts/raw-ptr-const.stderr
new file mode 100644
index 00000000000..974b1c3ff45
--- /dev/null
+++ b/src/test/ui/consts/raw-ptr-const.stderr
@@ -0,0 +1,8 @@
+error: untyped pointers are not allowed in constant
+  --> $DIR/raw-ptr-const.rs:7:1
+   |
+LL | const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/error-codes/E0730.rs b/src/test/ui/error-codes/E0730.rs
index 66a6e1c817a..30745814b4a 100644
--- a/src/test/ui/error-codes/E0730.rs
+++ b/src/test/ui/error-codes/E0730.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn is_123<const N: usize>(x: [u32; N]) -> bool {
     match x {
diff --git a/src/test/ui/error-codes/E0730.stderr b/src/test/ui/error-codes/E0730.stderr
index b0d43225be6..f915f6edef5 100644
--- a/src/test/ui/error-codes/E0730.stderr
+++ b/src/test/ui/error-codes/E0730.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/E0730.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[E0730]: cannot pattern-match on an array without a fixed length
   --> $DIR/E0730.rs:6:9
diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
index 632afb24aa5..67721780682 100644
--- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
@@ -7,7 +7,7 @@ LL |     let arr: [Option<String>; 2] = [None::<String>; 2];
    = help: the following implementations were found:
              <std::option::Option<T> as std::marker::Copy>
    = note: the `Copy` trait is required because the repeated element will be copied
-   = note: this array initializer can be evaluated at compile-time, see issue #48147 <https://github.com/rust-lang/rust/issues/49147> for more information
+   = note: this array initializer can be evaluated at compile-time, see issue #49147 <https://github.com/rust-lang/rust/issues/49147> for more information
    = help: add `#![feature(const_in_array_repeat_expressions)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied
diff --git a/src/test/ui/generic-associated-types/gat-incomplete-warning.stderr b/src/test/ui/generic-associated-types/gat-incomplete-warning.stderr
index 50f3c1e0d5a..0215ff395df 100644
--- a/src/test/ui/generic-associated-types/gat-incomplete-warning.stderr
+++ b/src/test/ui/generic-associated-types/gat-incomplete-warning.stderr
@@ -1,10 +1,11 @@
-warning: the feature `generic_associated_types` is incomplete and may cause the compiler to crash
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/gat-incomplete-warning.rs:3:12
    |
 LL | #![feature(generic_associated_types)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/hygiene/generic_params.stderr b/src/test/ui/hygiene/generic_params.stderr
index 94a1eca4953..4ca6d199835 100644
--- a/src/test/ui/hygiene/generic_params.stderr
+++ b/src/test/ui/hygiene/generic_params.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/generic_params.rs:6:37
    |
 LL | #![feature(decl_macro, rustc_attrs, 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/hygiene/issue-61574-const-parameters.stderr b/src/test/ui/hygiene/issue-61574-const-parameters.stderr
index 11dba87d97b..b351b8b73a0 100644
--- a/src/test/ui/hygiene/issue-61574-const-parameters.stderr
+++ b/src/test/ui/hygiene/issue-61574-const-parameters.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-61574-const-parameters.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
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/if-attrs/let-chains-attr.stderr b/src/test/ui/if-attrs/let-chains-attr.stderr
index 1a48fc12b8f..8b987471534 100644
--- a/src/test/ui/if-attrs/let-chains-attr.stderr
+++ b/src/test/ui/if-attrs/let-chains-attr.stderr
@@ -1,10 +1,11 @@
-warning: the feature `let_chains` is incomplete and may cause the compiler to crash
+warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/let-chains-attr.rs:3:12
    |
 LL | #![feature(let_chains)]
    |            ^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/impl-trait-in-bindings.rs b/src/test/ui/impl-trait-in-bindings.rs
index 2e9b6cd5c78..c7fae45d5ca 100644
--- a/src/test/ui/impl-trait-in-bindings.rs
+++ b/src/test/ui/impl-trait-in-bindings.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(impl_trait_in_bindings)]
-//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
 
 use std::fmt::Debug;
 
diff --git a/src/test/ui/impl-trait-in-bindings.stderr b/src/test/ui/impl-trait-in-bindings.stderr
index 2623d8e2d02..bf739d4722f 100644
--- a/src/test/ui/impl-trait-in-bindings.stderr
+++ b/src/test/ui/impl-trait-in-bindings.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/impl-trait-in-bindings.rs:3:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/impl-trait/bindings-opaque.rs b/src/test/ui/impl-trait/bindings-opaque.rs
index d4eef29ed32..d1f42be077d 100644
--- a/src/test/ui/impl-trait/bindings-opaque.rs
+++ b/src/test/ui/impl-trait/bindings-opaque.rs
@@ -1,5 +1,5 @@
 #![feature(impl_trait_in_bindings)]
-//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
 
 const FOO: impl Copy = 42;
 
diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr
index 14d33270ca5..6656968d79a 100644
--- a/src/test/ui/impl-trait/bindings-opaque.stderr
+++ b/src/test/ui/impl-trait/bindings-opaque.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/bindings-opaque.rs:1:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope
   --> $DIR/bindings-opaque.rs:11:17
diff --git a/src/test/ui/impl-trait/bindings.rs b/src/test/ui/impl-trait/bindings.rs
index 104a44d6566..fd79ba68fbd 100644
--- a/src/test/ui/impl-trait/bindings.rs
+++ b/src/test/ui/impl-trait/bindings.rs
@@ -1,5 +1,5 @@
 #![feature(impl_trait_in_bindings)]
-//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
 
 fn a<T: Clone>(x: T) {
     const foo: impl Clone = x;
diff --git a/src/test/ui/impl-trait/bindings.stderr b/src/test/ui/impl-trait/bindings.stderr
index 7d64980074a..e983fdecdba 100644
--- a/src/test/ui/impl-trait/bindings.stderr
+++ b/src/test/ui/impl-trait/bindings.stderr
@@ -22,13 +22,14 @@ error[E0435]: attempt to use a non-constant value in a constant
 LL |         const foo: impl Clone = x;
    |                                 ^ non-constant value
 
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/bindings.rs:1:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index 04b398f5b52..c78d4c4a8fd 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/bound-normalization-fail.rs:4:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
   --> $DIR/bound-normalization-fail.rs:27:32
diff --git a/src/test/ui/impl-trait/bound-normalization-pass.stderr b/src/test/ui/impl-trait/bound-normalization-pass.stderr
index fcc3cc51236..afc181a906a 100644
--- a/src/test/ui/impl-trait/bound-normalization-pass.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-pass.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/bound-normalization-pass.rs:5:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs
index f1b1656745e..fafab8a102a 100644
--- a/src/test/ui/impl-trait/example-calendar.rs
+++ b/src/test/ui/impl-trait/example-calendar.rs
@@ -2,6 +2,7 @@
 
 #![feature(fn_traits,
            step_trait,
+           step_trait_ext,
            unboxed_closures,
 )]
 
@@ -10,7 +11,6 @@
 //! Originally converted to Rust by [Daniel Keep](https://github.com/DanielKeep).
 
 use std::fmt::Write;
-use std::mem;
 
 /// Date representation.
 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
@@ -156,32 +156,16 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
     }
 }
 
-impl std::iter::Step for NaiveDate {
+unsafe impl std::iter::Step for NaiveDate {
     fn steps_between(_: &Self, _: &Self) -> Option<usize> {
         unimplemented!()
     }
 
-    fn replace_one(&mut self) -> Self {
-        mem::replace(self, NaiveDate(0, 0, 1))
+    fn forward_checked(start: Self, n: usize) -> Option<Self> {
+        Some((0..n).fold(start, |x, _| x.succ()))
     }
 
-    fn replace_zero(&mut self) -> Self {
-        mem::replace(self, NaiveDate(0, 0, 0))
-    }
-
-    fn add_one(&self) -> Self {
-        self.succ()
-    }
-
-    fn sub_one(&self) -> Self {
-        unimplemented!()
-    }
-
-    fn add_usize(&self, _: usize) -> Option<Self> {
-        unimplemented!()
-    }
-
-    fn sub_usize(&self, _: usize) -> Option<Self> {
+    fn backward_checked(_: Self, _: usize) -> Option<Self> {
         unimplemented!()
     }
 }
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
index 7d75f254bfe..2e96022318b 100644
--- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
+++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
@@ -1,6 +1,6 @@
 // edition:2018
 #![feature(impl_trait_in_bindings)]
-//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
 
 use std::io::Error;
 
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
index 39f5d3c6d8c..89a22f5e5d6 100644
--- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
+++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:2:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error[E0282]: type annotations needed for `impl std::future::Future`
   --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:9
diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr
index f53489a99f3..775f9702401 100644
--- a/src/test/ui/issues/issue-20005.stderr
+++ b/src/test/ui/issues/issue-20005.stderr
@@ -11,7 +11,7 @@ LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self> {
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
-LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: std::marker::Sized  {
+LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: std::marker::Sized {
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider relaxing the implicit `Sized` restriction
    |
diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr
index 283a5e04a8b..038490bbd7c 100644
--- a/src/test/ui/issues/issue-22872.stderr
+++ b/src/test/ui/issues/issue-22872.stderr
@@ -1,14 +1,16 @@
 error[E0277]: `<P as Process<'_>>::Item` is not an iterator
   --> $DIR/issue-22872.rs:20:40
    |
-LL | fn push_process<P>(process: P) where P: Process<'static> {
-   |                                                         - help: consider further restricting the associated type: `, <P as Process<'_>>::Item: std::iter::Iterator`
 LL |     let _: Box<dyn for<'b> Wrap<'b>> = Box::new(Wrapper(process));
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'_>>::Item` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `<P as Process<'_>>::Item`
    = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
    = note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
+help: consider further restricting the associated type
+   |
+LL | fn push_process<P>(process: P) where P: Process<'static>, <P as Process<'_>>::Item: std::iter::Iterator {
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr
index fbc72d063f3..3eb9d3c6203 100644
--- a/src/test/ui/issues/issue-27078.stderr
+++ b/src/test/ui/issues/issue-27078.stderr
@@ -2,14 +2,16 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
   --> $DIR/issue-27078.rs:5:12
    |
 LL |     fn foo(self) -> &'static i32 {
-   |            ^^^^                 - help: consider further restricting `Self`: `where Self: std::marker::Sized`
-   |            |
-   |            doesn't have a size known at compile-time
+   |            ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider further restricting `Self`
+   |
+LL |     fn foo(self) -> &'static i32 where Self: std::marker::Sized {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr
index 915bfffd6d5..0d4797a7a06 100644
--- a/src/test/ui/issues/issue-42312.stderr
+++ b/src/test/ui/issues/issue-42312.stderr
@@ -2,14 +2,16 @@ error[E0277]: the size for values of type `<Self as std::ops::Deref>::Target` ca
   --> $DIR/issue-42312.rs:4:12
    |
 LL |     fn baz(_: Self::Target) where Self: Deref {}
-   |            ^                                 - help: consider further restricting the associated type: `, <Self as std::ops::Deref>::Target: std::marker::Sized`
-   |            |
-   |            doesn't have a size known at compile-time
+   |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<Self as std::ops::Deref>::Target`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider further restricting the associated type
+   |
+LL |     fn baz(_: Self::Target) where Self: Deref, <Self as std::ops::Deref>::Target: std::marker::Sized {}
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time
   --> $DIR/issue-42312.rs:8:10
diff --git a/src/test/ui/issues/issue-59508-1.rs b/src/test/ui/issues/issue-59508-1.rs
index 4fbed9b08f2..a687a9e3be1 100644
--- a/src/test/ui/issues/issue-59508-1.rs
+++ b/src/test/ui/issues/issue-59508-1.rs
@@ -1,6 +1,6 @@
 #![allow(dead_code)]
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 // This test checks that generic parameter re-ordering diagnostic suggestions mention that
 // consts come after types and lifetimes when the `const_generics` feature is enabled.
diff --git a/src/test/ui/issues/issue-59508-1.stderr b/src/test/ui/issues/issue-59508-1.stderr
index 25efbb10529..85db20b13fb 100644
--- a/src/test/ui/issues/issue-59508-1.stderr
+++ b/src/test/ui/issues/issue-59508-1.stderr
@@ -4,13 +4,14 @@ error: lifetime parameters must be declared prior to type parameters
 LL |     pub fn do_things<T, 'a, 'b: 'a>() {
    |                     ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+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
    |
 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/issues/issue-71036.rs b/src/test/ui/issues/issue-71036.rs
new file mode 100644
index 00000000000..01d1cff42e4
--- /dev/null
+++ b/src/test/ui/issues/issue-71036.rs
@@ -0,0 +1,17 @@
+#![feature(unsize, dispatch_from_dyn)]
+
+use std::marker::Unsize;
+use std::ops::DispatchFromDyn;
+
+#[allow(unused)]
+struct Foo<'a, T: ?Sized> {
+    _inner: &'a &'a T,
+}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
+//~^ ERROR the trait bound `&'a T: std::marker::Unsize<&'a U>` is not satisfied
+//~| NOTE the trait `std::marker::Unsize<&'a U>` is not implemented for `&'a T`
+//~| NOTE all implementations of `Unsize` are provided automatically by the compiler
+//~| NOTE required because of the requirements on the impl
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-71036.stderr b/src/test/ui/issues/issue-71036.stderr
new file mode 100644
index 00000000000..57cf2468945
--- /dev/null
+++ b/src/test/ui/issues/issue-71036.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&'a T: std::marker::Unsize<&'a U>` is not satisfied
+  --> $DIR/issue-71036.rs:11:1
+   |
+LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unsize<&'a U>` is not implemented for `&'a T`
+   |
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+   = note: required because of the requirements on the impl of `std::ops::DispatchFromDyn<&'a &'a U>` for `&'a &'a T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lint/issue-71290-unused-paren-binop.rs b/src/test/ui/lint/issue-71290-unused-paren-binop.rs
new file mode 100644
index 00000000000..24d77e36d94
--- /dev/null
+++ b/src/test/ui/lint/issue-71290-unused-paren-binop.rs
@@ -0,0 +1,23 @@
+// check-pass
+// Make sure unused parens lint doesn't emit a false positive.
+// See https://github.com/rust-lang/rust/issues/71290 for details.
+#![deny(unused_parens)]
+
+fn x() -> u8 {
+    ({ 0 }) + 1
+}
+
+fn y() -> u8 {
+    ({ 0 } + 1)
+}
+
+pub fn foo(a: bool, b: bool) -> u8 {
+    (if a { 1 } else { 0 } + if b { 1 } else { 0 })
+}
+
+pub fn bar() -> u8 {
+    // Make sure nested expressions are handled correctly as well
+    ({ 0 } + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9)
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr
index a79fba9bf3f..bc0c5330324 100644
--- a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr
+++ b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr
@@ -1,4 +1,4 @@
-TokenStream [Ident { ident: "fn", span: #0 bytes(198..200) }, Ident { ident: "span_preservation", span: #0 bytes(201..218) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(218..220) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(228..231) }, Ident { ident: "tst", span: #0 bytes(232..235) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(236..237) }, Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(238), hi: BytePos(241), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(241..242) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(242..243) }, Ident { ident: "match", span: #0 bytes(289..294) }, Ident { ident: "tst", span: #0 bytes(295..298) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(483), hi: BytePos(486), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(487..489) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(487..489) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(490..492) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(492..493) }, Ident { ident: "_", span: #0 bytes(502..503) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(504..506) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(504..506) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(507..509) }], span: #0 bytes(299..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(516..517) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(517..518) }], span: #0 bytes(222..562) }]
+TokenStream [Ident { ident: "fn", span: #0 bytes(198..200) }, Ident { ident: "span_preservation", span: #0 bytes(201..218) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(218..220) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(228..231) }, Ident { ident: "tst", span: #0 bytes(232..235) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(236..237) }, Literal { kind: Integer, symbol: "123", suffix: None, span: #0 bytes(238..241) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(241..242) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(242..243) }, Ident { ident: "match", span: #0 bytes(289..294) }, Ident { ident: "tst", span: #0 bytes(295..298) }, Group { delimiter: Brace, stream: TokenStream [Literal { kind: Integer, symbol: "123", suffix: None, span: #0 bytes(483..486) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(487..489) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(487..489) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(490..492) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(492..493) }, Ident { ident: "_", span: #0 bytes(502..503) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(504..506) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(504..506) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(507..509) }], span: #0 bytes(299..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(516..517) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(517..518) }], span: #0 bytes(222..562) }]
 error: unnecessary trailing semicolon
   --> $DIR/redundant-semi-proc-macro.rs:9:19
    |
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr b/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr
index 0c3dbffeea6..bd50a27fd5e 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr
@@ -18,3 +18,4 @@ LL | fn f(t: &Ref2<dyn Test>) {
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0228`.
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr
index 9dbf7a78ed7..f06a9da1dee 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr
@@ -6,3 +6,4 @@ LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0228`.
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr
index d069f52ce47..51d8450af76 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr
@@ -6,3 +6,4 @@ LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0228`.
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
index 9c7b6b98f2e..f721bf39419 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
@@ -6,3 +6,4 @@ LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0228`.
diff --git a/src/test/ui/optimization-fuel-0.rs b/src/test/ui/optimization-fuel-0.rs
index f86972b7348..a97c5750f94 100644
--- a/src/test/ui/optimization-fuel-0.rs
+++ b/src/test/ui/optimization-fuel-0.rs
@@ -4,8 +4,7 @@
 
 use std::mem::size_of;
 
-// (#55495: The --error-format is to sidestep an issue in our test harness)
-// compile-flags: --error-format human -Z fuel=foo=0
+// compile-flags: -Z fuel=foo=0
 
 struct S1(u8, u16, u8);
 struct S2(u8, u16, u8);
diff --git a/src/test/ui/optimization-fuel-0.stderr b/src/test/ui/optimization-fuel-0.stderr
index 3ad405b2b50..f0e2ebfc37a 100644
--- a/src/test/ui/optimization-fuel-0.stderr
+++ b/src/test/ui/optimization-fuel-0.stderr
@@ -1 +1,4 @@
-optimization-fuel-exhausted: Reorder fields of "S1"
+warning: optimization-fuel-exhausted: Reorder fields of "S1"
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/optimization-fuel-1.rs b/src/test/ui/optimization-fuel-1.rs
index 98283066361..a09f91c68ab 100644
--- a/src/test/ui/optimization-fuel-1.rs
+++ b/src/test/ui/optimization-fuel-1.rs
@@ -4,8 +4,7 @@
 
 use std::mem::size_of;
 
-// (#55495: The --error-format is to sidestep an issue in our test harness)
-// compile-flags: --error-format human -Z fuel=foo=1
+// compile-flags: -Z fuel=foo=1
 
 struct S1(u8, u16, u8);
 struct S2(u8, u16, u8);
diff --git a/src/test/ui/optimization-fuel-1.stderr b/src/test/ui/optimization-fuel-1.stderr
index 197e45219c3..53eafb05830 100644
--- a/src/test/ui/optimization-fuel-1.stderr
+++ b/src/test/ui/optimization-fuel-1.stderr
@@ -1 +1,4 @@
-optimization-fuel-exhausted: Reorder fields of "S2"
+warning: optimization-fuel-exhausted: Reorder fields of "S2"
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
index 7678ee6c821..214467793bc 100644
--- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
+++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
@@ -42,13 +42,14 @@ LL |     type W where Self: Eq;
    |                          |
    |                          help: provide a definition for the type: `= <type>;`
 
-warning: the feature `generic_associated_types` is incomplete and may cause the compiler to crash
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/impl-item-type-no-body-semantic-fail.rs:1:12
    |
 LL | #![feature(generic_associated_types)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
 
 error[E0202]: associated types are not yet supported in inherent impls (see #8995)
   --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:5
diff --git a/src/test/ui/parser/issue-3036.stderr b/src/test/ui/parser/issue-3036.stderr
index b6557163d45..e5f5a7d8968 100644
--- a/src/test/ui/parser/issue-3036.stderr
+++ b/src/test/ui/parser/issue-3036.stderr
@@ -1,4 +1,4 @@
-error: expected `;`, found ``}``
+error: expected `;`, found `}`
   --> $DIR/issue-3036.rs:5:14
    |
 LL |     let x = 3
diff --git a/src/test/ui/parser/recover-missing-semi.stderr b/src/test/ui/parser/recover-missing-semi.stderr
index 2f2464d3629..ba479828538 100644
--- a/src/test/ui/parser/recover-missing-semi.stderr
+++ b/src/test/ui/parser/recover-missing-semi.stderr
@@ -1,4 +1,4 @@
-error: expected `;`, found `keyword `let``
+error: expected `;`, found keyword `let`
   --> $DIR/recover-missing-semi.rs:2:22
    |
 LL |     let _: usize = ()
@@ -7,7 +7,7 @@ LL |     let _: usize = ()
 LL |     let _ = 3;
    |     --- unexpected token
 
-error: expected `;`, found `keyword `return``
+error: expected `;`, found keyword `return`
   --> $DIR/recover-missing-semi.rs:9:22
    |
 LL |     let _: usize = ()
diff --git a/src/test/ui/proc-macro/debug/auxiliary/macro-dump-debug.rs b/src/test/ui/proc-macro/debug/auxiliary/macro-dump-debug.rs
new file mode 100644
index 00000000000..56ad0612f74
--- /dev/null
+++ b/src/test/ui/proc-macro/debug/auxiliary/macro-dump-debug.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![crate_name = "macro_dump_debug"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn dump_debug(tokens: TokenStream) -> TokenStream {
+    eprintln!("{:?}", tokens);
+    eprintln!("{:#?}", tokens);
+    TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/debug/dump-debug.rs b/src/test/ui/proc-macro/debug/dump-debug.rs
new file mode 100644
index 00000000000..0ed36b690f4
--- /dev/null
+++ b/src/test/ui/proc-macro/debug/dump-debug.rs
@@ -0,0 +1,40 @@
+// run-pass
+// aux-build:macro-dump-debug.rs
+
+extern crate macro_dump_debug;
+use macro_dump_debug::dump_debug;
+
+dump_debug! {
+    ident   // ident
+    r#ident // raw ident
+    ,       // alone punct
+    ==>     // joint punct
+    ()      // empty group
+    [_]     // nonempty group
+
+    // unsuffixed literals
+    0
+    1.0
+    "S"
+    b"B"
+    r"R"
+    r##"R"##
+    br"BR"
+    br##"BR"##
+    'C'
+    b'B'
+
+    // suffixed literals
+    0q
+    1.0q
+    "S"q
+    b"B"q
+    r"R"q
+    r##"R"##q
+    br"BR"q
+    br##"BR"##q
+    'C'q
+    b'B'q
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/debug/dump-debug.stderr b/src/test/ui/proc-macro/debug/dump-debug.stderr
new file mode 100644
index 00000000000..0aedefd4e60
--- /dev/null
+++ b/src/test/ui/proc-macro/debug/dump-debug.stderr
@@ -0,0 +1,166 @@
+TokenStream [Ident { ident: "ident", span: #0 bytes(130..135) }, Ident { ident: "r#ident", span: #0 bytes(151..158) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(176..177) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(203..205) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(203..205) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(205..206) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(230..232) }, Group { delimiter: Bracket, stream: TokenStream [Ident { ident: "_", span: #0 bytes(258..259) }], span: #0 bytes(257..260) }, Literal { kind: Integer, symbol: "0", suffix: None, span: #0 bytes(315..316) }, Literal { kind: Float, symbol: "1.0", suffix: None, span: #0 bytes(321..324) }, Literal { kind: Str, symbol: "S", suffix: None, span: #0 bytes(329..332) }, Literal { kind: ByteStr, symbol: "B", suffix: None, span: #0 bytes(337..341) }, Literal { kind: StrRaw(0), symbol: "R", suffix: None, span: #0 bytes(346..350) }, Literal { kind: StrRaw(2), symbol: "R", suffix: None, span: #0 bytes(355..363) }, Literal { kind: ByteStrRaw(0), symbol: "BR", suffix: None, span: #0 bytes(368..374) }, Literal { kind: ByteStrRaw(2), symbol: "BR", suffix: None, span: #0 bytes(379..389) }, Literal { kind: Char, symbol: "C", suffix: None, span: #0 bytes(394..397) }, Literal { kind: Byte, symbol: "B", suffix: None, span: #0 bytes(402..406) }, Literal { kind: Integer, symbol: "0", suffix: Some("q"), span: #0 bytes(437..439) }, Literal { kind: Float, symbol: "1.0", suffix: Some("q"), span: #0 bytes(444..448) }, Literal { kind: Str, symbol: "S", suffix: Some("q"), span: #0 bytes(453..457) }, Literal { kind: ByteStr, symbol: "B", suffix: Some("q"), span: #0 bytes(462..467) }, Literal { kind: StrRaw(0), symbol: "R", suffix: Some("q"), span: #0 bytes(472..477) }, Literal { kind: StrRaw(2), symbol: "R", suffix: Some("q"), span: #0 bytes(482..491) }, Literal { kind: ByteStrRaw(0), symbol: "BR", suffix: Some("q"), span: #0 bytes(496..503) }, Literal { kind: ByteStrRaw(2), symbol: "BR", suffix: Some("q"), span: #0 bytes(508..519) }, Literal { kind: Char, symbol: "C", suffix: Some("q"), span: #0 bytes(524..528) }, Literal { kind: Byte, symbol: "B", suffix: Some("q"), span: #0 bytes(533..538) }]
+TokenStream [
+    Ident {
+        ident: "ident",
+        span: #0 bytes(130..135),
+    },
+    Ident {
+        ident: "r#ident",
+        span: #0 bytes(151..158),
+    },
+    Punct {
+        ch: ',',
+        spacing: Alone,
+        span: #0 bytes(176..177),
+    },
+    Punct {
+        ch: '=',
+        spacing: Joint,
+        span: #0 bytes(203..205),
+    },
+    Punct {
+        ch: '=',
+        spacing: Joint,
+        span: #0 bytes(203..205),
+    },
+    Punct {
+        ch: '>',
+        spacing: Alone,
+        span: #0 bytes(205..206),
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [],
+        span: #0 bytes(230..232),
+    },
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "_",
+                span: #0 bytes(258..259),
+            },
+        ],
+        span: #0 bytes(257..260),
+    },
+    Literal {
+        kind: Integer,
+        symbol: "0",
+        suffix: None,
+        span: #0 bytes(315..316),
+    },
+    Literal {
+        kind: Float,
+        symbol: "1.0",
+        suffix: None,
+        span: #0 bytes(321..324),
+    },
+    Literal {
+        kind: Str,
+        symbol: "S",
+        suffix: None,
+        span: #0 bytes(329..332),
+    },
+    Literal {
+        kind: ByteStr,
+        symbol: "B",
+        suffix: None,
+        span: #0 bytes(337..341),
+    },
+    Literal {
+        kind: StrRaw(0),
+        symbol: "R",
+        suffix: None,
+        span: #0 bytes(346..350),
+    },
+    Literal {
+        kind: StrRaw(2),
+        symbol: "R",
+        suffix: None,
+        span: #0 bytes(355..363),
+    },
+    Literal {
+        kind: ByteStrRaw(0),
+        symbol: "BR",
+        suffix: None,
+        span: #0 bytes(368..374),
+    },
+    Literal {
+        kind: ByteStrRaw(2),
+        symbol: "BR",
+        suffix: None,
+        span: #0 bytes(379..389),
+    },
+    Literal {
+        kind: Char,
+        symbol: "C",
+        suffix: None,
+        span: #0 bytes(394..397),
+    },
+    Literal {
+        kind: Byte,
+        symbol: "B",
+        suffix: None,
+        span: #0 bytes(402..406),
+    },
+    Literal {
+        kind: Integer,
+        symbol: "0",
+        suffix: Some("q"),
+        span: #0 bytes(437..439),
+    },
+    Literal {
+        kind: Float,
+        symbol: "1.0",
+        suffix: Some("q"),
+        span: #0 bytes(444..448),
+    },
+    Literal {
+        kind: Str,
+        symbol: "S",
+        suffix: Some("q"),
+        span: #0 bytes(453..457),
+    },
+    Literal {
+        kind: ByteStr,
+        symbol: "B",
+        suffix: Some("q"),
+        span: #0 bytes(462..467),
+    },
+    Literal {
+        kind: StrRaw(0),
+        symbol: "R",
+        suffix: Some("q"),
+        span: #0 bytes(472..477),
+    },
+    Literal {
+        kind: StrRaw(2),
+        symbol: "R",
+        suffix: Some("q"),
+        span: #0 bytes(482..491),
+    },
+    Literal {
+        kind: ByteStrRaw(0),
+        symbol: "BR",
+        suffix: Some("q"),
+        span: #0 bytes(496..503),
+    },
+    Literal {
+        kind: ByteStrRaw(2),
+        symbol: "BR",
+        suffix: Some("q"),
+        span: #0 bytes(508..519),
+    },
+    Literal {
+        kind: Char,
+        symbol: "C",
+        suffix: Some("q"),
+        span: #0 bytes(524..528),
+    },
+    Literal {
+        kind: Byte,
+        symbol: "B",
+        suffix: Some("q"),
+        span: #0 bytes(533..538),
+    },
+]
diff --git a/src/test/ui/process-termination/process-termination-blocking-io.rs b/src/test/ui/process-termination/process-termination-blocking-io.rs
new file mode 100644
index 00000000000..f306a61a538
--- /dev/null
+++ b/src/test/ui/process-termination/process-termination-blocking-io.rs
@@ -0,0 +1,19 @@
+// program should terminate even if a thread is blocked on I/O.
+// https://github.com/fortanix/rust-sgx/issues/109
+
+// run-pass
+// ignore-emscripten no threads support
+
+use std::{net::TcpListener, sync::mpsc, thread};
+
+fn main() {
+    let (tx, rx) = mpsc::channel();
+    thread::spawn(move || {
+        let listen = TcpListener::bind("0.0.0.0:0").unwrap();
+        tx.send(()).unwrap();
+        while let Ok(_) = listen.accept() {}
+    });
+    rx.recv().unwrap();
+    for _ in 0..3 { thread::yield_now(); }
+    println!("Exiting main thread");
+}
diff --git a/src/test/ui/process-termination/process-termination-simple.rs b/src/test/ui/process-termination/process-termination-simple.rs
new file mode 100644
index 00000000000..8f2e5b94c3a
--- /dev/null
+++ b/src/test/ui/process-termination/process-termination-simple.rs
@@ -0,0 +1,13 @@
+// program should terminate when std::process::exit is called from any thread
+
+// run-pass
+// ignore-emscripten no threads support
+
+use std::{process, thread};
+
+fn main() {
+    let h = thread::spawn(|| {
+        process::exit(0);
+    });
+    let _ = h.join();
+}
diff --git a/src/test/ui/regions/issue-72051-member-region-hang.rs b/src/test/ui/regions/issue-72051-member-region-hang.rs
new file mode 100644
index 00000000000..b7340b79d68
--- /dev/null
+++ b/src/test/ui/regions/issue-72051-member-region-hang.rs
@@ -0,0 +1,7 @@
+// Regression test for #72051, hang when resolving regions.
+
+// check-pass
+// edition:2018
+
+pub async fn query<'a>(_: &(), _: &(), _: (&(dyn std::any::Any + 'a),) ) {}
+fn main() {}
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
index b6a08351609..f09ab3bf919 100644
--- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
+++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
@@ -1,5 +1,5 @@
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 fn f<T>() {
     extern "C" {
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
index 6076328b12f..7f8151db06f 100644
--- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
+++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -40,13 +40,14 @@ LL | fn i<const N: usize>() {
 LL |     static a: [u8; N] = [0; N];
    |                             ^ use of generic parameter from outer function
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-65035-static-with-parent-generics.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 5 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2457/auxiliary/mod_file_nonascii_with_path_allowed-aux.rs b/src/test/ui/rfc-2457/auxiliary/mod_file_nonascii_with_path_allowed-aux.rs
new file mode 100644
index 00000000000..e373b64384f
--- /dev/null
+++ b/src/test/ui/rfc-2457/auxiliary/mod_file_nonascii_with_path_allowed-aux.rs
@@ -0,0 +1 @@
+pub trait Foo {}
diff --git a/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.rs b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.rs
new file mode 100644
index 00000000000..efd2932f152
--- /dev/null
+++ b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.rs
@@ -0,0 +1,6 @@
+#![feature(non_ascii_idents)]
+
+mod řųśť; //~ trying to load file for
+//~^ file not found for
+
+fn main() {}
diff --git a/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
new file mode 100644
index 00000000000..be729836f4f
--- /dev/null
+++ b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
@@ -0,0 +1,20 @@
+error[E0583]: file not found for module `řųśť`
+  --> $DIR/mod_file_nonascii_forbidden.rs:3:1
+   |
+LL | mod řųśť;
+   | ^^^^^^^^^
+   |
+   = help: to create the module `řųśť`, create file "$DIR/řųśť.rs"
+
+error[E0754]: trying to load file for module `řųśť` with non ascii identifer name
+  --> $DIR/mod_file_nonascii_forbidden.rs:3:5
+   |
+LL | mod řųśť;
+   |     ^^^^
+   |
+   = help: consider using `#[path]` attribute to specify filesystem path
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0583, E0754.
+For more information about an error, try `rustc --explain E0583`.
diff --git a/src/test/ui/rfc-2457/mod_file_nonascii_with_path_allowed.rs b/src/test/ui/rfc-2457/mod_file_nonascii_with_path_allowed.rs
new file mode 100644
index 00000000000..e9f3fba2fb0
--- /dev/null
+++ b/src/test/ui/rfc-2457/mod_file_nonascii_with_path_allowed.rs
@@ -0,0 +1,7 @@
+// check-pass
+#![feature(non_ascii_idents)]
+
+#[path="auxiliary/mod_file_nonascii_with_path_allowed-aux.rs"]
+mod řųśť;
+
+fn main() {}
diff --git a/src/test/ui/rfc-2457/mod_inline_nonascii_allowed.rs b/src/test/ui/rfc-2457/mod_inline_nonascii_allowed.rs
new file mode 100644
index 00000000000..dd27da432ba
--- /dev/null
+++ b/src/test/ui/rfc-2457/mod_inline_nonascii_allowed.rs
@@ -0,0 +1,8 @@
+// check-pass
+#![feature(non_ascii_idents)]
+
+mod řųśť {
+    const IS_GREAT: bool = true;
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.rs b/src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.rs
new file mode 100644
index 00000000000..a408c975716
--- /dev/null
+++ b/src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.rs
@@ -0,0 +1,6 @@
+#![feature(non_ascii_idents)]
+
+#[no_mangle]
+pub fn řųśť() {}  //~ `#[no_mangle]` requires ASCII identifier
+
+fn main() {}
diff --git a/src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.stderr b/src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.stderr
new file mode 100644
index 00000000000..4ca83e41032
--- /dev/null
+++ b/src/test/ui/rfc-2457/no_mangle_nonascii_forbidden.stderr
@@ -0,0 +1,9 @@
+error[E0754]: `#[no_mangle]` requires ASCII identifier
+  --> $DIR/no_mangle_nonascii_forbidden.rs:4:1
+   |
+LL | pub fn řųśť() {}
+   | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0754`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 4f11c306f50..4c3a00e5f35 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -499,19 +499,22 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if`- and `while`-expressions
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/disallowed-positions.rs:20: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: the feature `let_chains` is incomplete and may cause the compiler to crash
+warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/disallowed-positions.rs:22:12
    |
 LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
    |            ^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
 
 error[E0658]: `match` is not allowed in a `const`
   --> $DIR/disallowed-positions.rs:218:17
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
index 5769366fb45..bf082932bd6 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
@@ -1,5 +1,5 @@
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `raw_dylib` is incomplete
 
 #[link(name="foo")]
 extern {
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
index c7765a453c4..5d8545b5062 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
@@ -1,10 +1,11 @@
-warning: the feature `raw_dylib` is incomplete and may cause the compiler to crash
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/link-ordinal-and-name.rs:1:12
    |
 LL | #![feature(raw_dylib)]
    |            ^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
 
 error: cannot use `#[link_name]` with `#[link_ordinal]`
   --> $DIR/link-ordinal-and-name.rs:7:5
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
index 82fb1151c23..ea633c5bcce 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
@@ -1,5 +1,5 @@
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `raw_dylib` is incomplete
 
 #[link(name="foo")]
 extern {
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
index 4826c46e90c..8453a3966be 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
@@ -1,10 +1,11 @@
-warning: the feature `raw_dylib` is incomplete and may cause the compiler to crash
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/link-ordinal-invalid-format.rs:1:12
    |
 LL | #![feature(raw_dylib)]
    |            ^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
 
 error: illegal ordinal format in `link_ordinal`
   --> $DIR/link-ordinal-invalid-format.rs:6:5
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
index 69596ad04ff..55cc329dc59 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
@@ -1,5 +1,5 @@
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `raw_dylib` is incomplete
 
 #[link(name="foo")]
 extern {
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
index f8bfe5a62b8..35f9b53fdf7 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
@@ -1,10 +1,11 @@
-warning: the feature `raw_dylib` is incomplete and may cause the compiler to crash
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/link-ordinal-too-large.rs:1:12
    |
 LL | #![feature(raw_dylib)]
    |            ^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
 
 error: ordinal value in `link_ordinal` is too large: `18446744073709551616`
   --> $DIR/link-ordinal-too-large.rs:6:5
diff --git a/src/test/ui/sanitize/issue-72154-lifetime-markers.rs b/src/test/ui/sanitize/issue-72154-lifetime-markers.rs
new file mode 100644
index 00000000000..458f99143b6
--- /dev/null
+++ b/src/test/ui/sanitize/issue-72154-lifetime-markers.rs
@@ -0,0 +1,31 @@
+// Regression test for issue 72154, where the use of AddressSanitizer enabled
+// emission of lifetime markers during codegen, while at the same time asking
+// always inliner pass not to insert them.  This eventually lead to a
+// miscompilation which was subsequently detected by AddressSanitizer as UB.
+//
+// needs-sanitizer-support
+// only-x86_64
+//
+// compile-flags: -Copt-level=0 -Zsanitizer=address
+// run-pass
+
+pub struct Wrap {
+    pub t: [usize; 1]
+}
+
+impl Wrap {
+    #[inline(always)]
+    pub fn new(t: [usize; 1]) -> Self {
+        Wrap { t }
+    }
+}
+
+#[inline(always)]
+pub fn assume_init() -> [usize; 1] {
+    [1234]
+}
+
+fn main() {
+    let x: [usize; 1] = assume_init();
+    Wrap::new(x);
+}
diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.rs b/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.rs
new file mode 100644
index 00000000000..319789c4ec2
--- /dev/null
+++ b/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.rs
@@ -0,0 +1,18 @@
+// Regression test for #70813 (this used to trigger a debug assertion)
+
+trait Trait {}
+
+struct S;
+
+impl<'a> Trait for &'a mut S {}
+
+fn foo<X>(_: X)
+where
+    for<'b> &'b X: Trait,
+{
+}
+
+fn main() {
+    let s = S;
+    foo::<S>(s); //~ ERROR the trait bound `for<'b> &'b S: Trait` is not satisfied
+}
diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr
new file mode 100644
index 00000000000..83de3c4cfe0
--- /dev/null
+++ b/src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `for<'b> &'b S: Trait` is not satisfied
+  --> $DIR/imm-ref-trait-object-literal-bound-regions.rs:17:5
+   |
+LL | fn foo<X>(_: X)
+   |    --- required by a bound in this
+LL | where
+LL |     for<'b> &'b X: Trait,
+   |                    ----- required by this bound in `foo`
+...
+LL |     foo::<S>(s);
+   |     ^^^^^^^^ the trait `for<'b> Trait` is not implemented for `&'b S`
+   |
+   = help: the following implementations were found:
+             <&'a mut S as Trait>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr
index 6fc629b33a2..fb0914a8743 100644
--- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr
+++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr
@@ -10,7 +10,7 @@ LL | fn qux(_: impl std::fmt::Debug) {}
    = help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
 help: introduce a type parameter with a trait bound instead of using `impl Trait`
    |
-LL | fn foo<I: Iterator>(constraints: I) where <I as std::iter::Iterator>::Item: std::fmt::Debug  {
+LL | fn foo<I: Iterator>(constraints: I) where <I as std::iter::Iterator>::Item: std::fmt::Debug {
    |       ^^^^^^^^^^^^^              ^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `<impl Iterator as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
@@ -25,7 +25,7 @@ LL | fn qux(_: impl std::fmt::Debug) {}
    = help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
 help: introduce a type parameter with a trait bound instead of using `impl Trait`
    |
-LL | fn bar<T, I: Iterator>(t: T, constraints: I) where T: std::fmt::Debug, <I as std::iter::Iterator>::Item: std::fmt::Debug  {
+LL | fn bar<T, I: Iterator>(t: T, constraints: I) where T: std::fmt::Debug, <I as std::iter::Iterator>::Item: std::fmt::Debug {
    |         ^^^^^^^^^^^^^                     ^                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `<impl Iterator as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
@@ -40,7 +40,7 @@ LL | fn qux(_: impl std::fmt::Debug) {}
    = help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
 help: introduce a type parameter with a trait bound instead of using `impl Trait`
    |
-LL | fn baz<I: Iterator>(t: impl std::fmt::Debug, constraints: I) where <I as std::iter::Iterator>::Item: std::fmt::Debug  {
+LL | fn baz<I: Iterator>(t: impl std::fmt::Debug, constraints: I) where <I as std::iter::Iterator>::Item: std::fmt::Debug {
    |       ^^^^^^^^^^^^^                                       ^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `<impl Iterator as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
@@ -55,7 +55,7 @@ LL | fn qux(_: impl std::fmt::Debug) {}
    = help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator as std::iter::Iterator>::Item`
 help: introduce a type parameter with a trait bound instead of using `impl Trait`
    |
-LL | fn bat<I, T: std::fmt::Debug, U: Iterator>(t: T, constraints: U, _: I) where <U as std::iter::Iterator>::Item: std::fmt::Debug  {
+LL | fn bat<I, T: std::fmt::Debug, U: Iterator>(t: T, constraints: U, _: I) where <U as std::iter::Iterator>::Item: std::fmt::Debug {
    |                             ^^^^^^^^^^^^^                     ^        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item` doesn't implement `std::fmt::Debug`
@@ -70,7 +70,7 @@ LL | fn qux(_: impl std::fmt::Debug) {}
    = help: the trait `std::fmt::Debug` is not implemented for `<impl Iterator + std::fmt::Debug as std::iter::Iterator>::Item`
 help: introduce a type parameter with a trait bound instead of using `impl Trait`
    |
-LL | fn bak<I: Iterator + std::fmt::Debug>(constraints: I) where <I as std::iter::Iterator>::Item: std::fmt::Debug  {
+LL | fn bak<I: Iterator + std::fmt::Debug>(constraints: I) where <I as std::iter::Iterator>::Item: std::fmt::Debug {
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
index ef484e94729..a8ea2147961 100644
--- a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
+++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
@@ -8,9 +8,12 @@ LL |     type Assoc: Child<Self::Ty>;
    |                 --------------- required by this bound in `Parent`
 ...
 LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
-   |                   ^^^^^^                              - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
-   |                   |
-   |                   the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+   |                   ^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+   |
+help: consider further restricting the associated type
+   |
+LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> where <T as Parent>::Assoc: Child<A> {
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
   --> $DIR/missing-assoc-type-bound-restriction.rs:20:18
@@ -21,13 +24,14 @@ LL |     type Ty;
 LL |     type Assoc: Child<Self::Ty>;
    |                 --------------- required by this bound in `Parent`
 ...
-LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
-   |                                                       - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
-...
 LL |     type Assoc = ChildWrapper<T::Assoc>;
    |                  ^^^^^^^^^^^^^^^^^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
    |
    = note: required because of the requirements on the impl of `Child<A>` for `ChildWrapper<<T as Parent>::Assoc>`
+help: consider further restricting the associated type
+   |
+LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> where <T as Parent>::Assoc: Child<A> {
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
   --> $DIR/missing-assoc-type-bound-restriction.rs:20:5
@@ -38,11 +42,13 @@ LL |     type Ty;
 LL |     type Assoc: Child<Self::Ty>;
    |                 --------------- required by this bound in `Parent`
 ...
-LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
-   |                                                       - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
-...
 LL |     type Assoc = ChildWrapper<T::Assoc>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+   |
+help: consider further restricting the associated type
+   |
+LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> where <T as Parent>::Assoc: Child<A> {
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
index f5ff54cc916..2630cf1affa 100644
--- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
@@ -252,5 +252,5 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell
 
 error: aborting due to 28 previous errors
 
-Some errors have detailed explanations: E0106, E0107.
+Some errors have detailed explanations: E0106, E0107, E0228.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-const.rs b/src/test/ui/type-alias-impl-trait/assoc-type-const.rs
index 7f3f86e4df0..d53f562e99f 100644
--- a/src/test/ui/type-alias-impl-trait/assoc-type-const.rs
+++ b/src/test/ui/type-alias-impl-trait/assoc-type-const.rs
@@ -4,7 +4,7 @@
 
 #![feature(type_alias_impl_trait)]
 #![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `const_generics` is incomplete
 
 trait UnwrapItemsExt<'a, const C: usize> {
     type Iter;
diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr
index 77cd7f4b93a..e0c1b023861 100644
--- a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr
+++ b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr
@@ -1,10 +1,11 @@
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/assoc-type-const.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
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs
index 0fd4d26ef60..bc2bf9eca93 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs
@@ -6,7 +6,7 @@
 // Specifically, this line requires `impl_trait_in_bindings` to be enabled:
 // https://github.com/rust-lang/rust/blob/481068a707679257e2a738b40987246e0420e787/src/librustc_typeck/check/mod.rs#L856
 #![feature(impl_trait_in_bindings)]
-//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
 
 // Ensures that `const` items can constrain an opaque `impl Trait`.
 
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr
index 5efb992a210..b0593d51a25 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr
@@ -1,10 +1,11 @@
-warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/type-alias-impl-trait-const.rs:8:12
    |
 LL | #![feature(impl_trait_in_bindings)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/type/type-params-in-different-spaces-2.stderr b/src/test/ui/type/type-params-in-different-spaces-2.stderr
index 7ce249a60b8..e0039f2a316 100644
--- a/src/test/ui/type/type-params-in-different-spaces-2.stderr
+++ b/src/test/ui/type/type-params-in-different-spaces-2.stderr
@@ -4,10 +4,13 @@ error[E0277]: the trait bound `Self: Tr<U>` is not satisfied
 LL |     fn op(_: T) -> Self;
    |     -------------------- required by `Tr::op`
 ...
-LL |     fn test<U>(u: U) -> Self {
-   |                             - help: consider further restricting `Self`: `where Self: Tr<U>`
 LL |         Tr::op(u)
    |         ^^^^^^ the trait `Tr<U>` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn test<U>(u: U) -> Self where Self: Tr<U> {
+   |                              ^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `Self: Tr<U>` is not satisfied
   --> $DIR/type-params-in-different-spaces-2.rs:16:9
@@ -15,10 +18,13 @@ error[E0277]: the trait bound `Self: Tr<U>` is not satisfied
 LL |     fn op(_: T) -> Self;
    |     -------------------- required by `Tr::op`
 ...
-LL |     fn test<U>(u: U) -> Self {
-   |                             - help: consider further restricting `Self`: `where Self: Tr<U>`
 LL |         Tr::op(u)
    |         ^^^^^^ the trait `Tr<U>` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn test<U>(u: U) -> Self where Self: Tr<U> {
+   |                              ^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed
index 7a108d880be..dd1195b99f6 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed
@@ -7,7 +7,7 @@ trait Trait {
     type AssocType;
     fn dummy(&self) { }
 }
-fn bar<T:Trait+Send>() where <T as Trait>::AssocType: std::marker::Send  {
+fn bar<T:Trait+Send>() where <T as Trait>::AssocType: std::marker::Send {
     is_send::<T::AssocType>(); //~ ERROR E0277
 }
 
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
index e64acfc54ff..f97d41637ba 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
@@ -1,8 +1,6 @@
 error[E0277]: `<T as Trait>::AssocType` cannot be sent between threads safely
   --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5
    |
-LL | fn bar<T:Trait+Send>() {
-   |                       - help: consider further restricting the associated type: `where <T as Trait>::AssocType: std::marker::Send`
 LL |     is_send::<T::AssocType>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
 ...
@@ -10,6 +8,10 @@ LL | fn is_send<T:Send>() {
    |              ---- required by this bound in `is_send`
    |
    = help: the trait `std::marker::Send` is not implemented for `<T as Trait>::AssocType`
+help: consider further restricting the associated type
+   |
+LL | fn bar<T:Trait+Send>() where <T as Trait>::AssocType: std::marker::Send {
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
index fe242e6a909..2c595833cd1 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
@@ -18,4 +18,5 @@ LL |     x: Box<dyn Debug + '_>,
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0228.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr
index cf8459609b6..828e8bc9f4a 100644
--- a/src/test/ui/unsized3.stderr
+++ b/src/test/ui/unsized3.stderr
@@ -31,8 +31,8 @@ LL | fn f4<X: T>(x: &X) {
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
-LL | fn f4<X: T +  ?Sized>(x: &X) {
-   |            ^^^^^^^^^
+LL | fn f4<X: T + ?Sized>(x: &X) {
+   |            ^^^^^^^^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:33:8
diff --git a/src/test/ui/wf/wf-trait-associated-type-trait.stderr b/src/test/ui/wf/wf-trait-associated-type-trait.stderr
index 70cf88f262f..e2892e3d248 100644
--- a/src/test/ui/wf/wf-trait-associated-type-trait.stderr
+++ b/src/test/ui/wf/wf-trait-associated-type-trait.stderr
@@ -3,12 +3,14 @@ error[E0277]: the trait bound `<Self as SomeTrait>::Type1: std::marker::Copy` is
    |
 LL | struct IsCopy<T:Copy> { x: T }
    |                 ---- required by this bound in `IsCopy`
-LL | 
-LL | trait SomeTrait {
-   |                - help: consider further restricting the associated type: `where <Self as SomeTrait>::Type1: std::marker::Copy`
-LL |     type Type1;
+...
 LL |     type Type2 = IsCopy<Self::Type1>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `<Self as SomeTrait>::Type1`
+   |
+help: consider further restricting the associated type
+   |
+LL | trait SomeTrait where <Self as SomeTrait>::Type1: std::marker::Copy {
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr
index ed563af5928..23d886e25ff 100644
--- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr
+++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr
@@ -5,9 +5,12 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    |              -- required by this bound in `Bar`
 ...
 LL |     fn bar(&self, x: &Bar<Self>) {
-   |                      ^^^^^^^^^^ - help: consider further restricting `Self`: `where Self: std::cmp::Eq`
-   |                      |
-   |                      the trait `std::cmp::Eq` is not implemented for `Self`
+   |                      ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar(&self, x: &Bar<Self>) where Self: std::cmp::Eq {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-default-fn-ret.stderr b/src/test/ui/wf/wf-trait-default-fn-ret.stderr
index 57cf1e9e6da..02140640172 100644
--- a/src/test/ui/wf/wf-trait-default-fn-ret.stderr
+++ b/src/test/ui/wf/wf-trait-default-fn-ret.stderr
@@ -5,9 +5,12 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    |              -- required by this bound in `Bar`
 ...
 LL |     fn bar(&self) -> Bar<Self> {
-   |                      ^^^^^^^^^- help: consider further restricting `Self`: `where Self: std::cmp::Eq`
-   |                      |
-   |                      the trait `std::cmp::Eq` is not implemented for `Self`
+   |                      ^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar(&self) -> Bar<Self> where Self: std::cmp::Eq {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr
index 534bf4d3448..3664c8b25aa 100644
--- a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr
@@ -5,9 +5,12 @@ LL | trait Bar<T:Eq+?Sized> { }
    |             -- required by this bound in `Bar`
 ...
 LL |     fn bar<A>(&self) where A: Bar<Self> {
-   |                               ^^^^^^^^^- help: consider further restricting `Self`: `, Self: std::cmp::Eq`
-   |                               |
-   |                               the trait `std::cmp::Eq` is not implemented for `Self`
+   |                               ^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar<A>(&self) where A: Bar<Self>, Self: std::cmp::Eq {
+   |                                        ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr
index 494619a2f29..b5f5f70ce81 100644
--- a/src/test/ui/wf/wf-trait-fn-arg.stderr
+++ b/src/test/ui/wf/wf-trait-fn-arg.stderr
@@ -5,9 +5,12 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    |              -- required by this bound in `Bar`
 ...
 LL |     fn bar(&self, x: &Bar<Self>);
-   |                      ^^^^^^^^^^ - help: consider further restricting `Self`: `where Self: std::cmp::Eq`
-   |                      |
-   |                      the trait `std::cmp::Eq` is not implemented for `Self`
+   |                      ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar(&self, x: &Bar<Self>) where Self: std::cmp::Eq;
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-fn-ret.stderr b/src/test/ui/wf/wf-trait-fn-ret.stderr
index 6a3381d9a22..5e7d8cbfea6 100644
--- a/src/test/ui/wf/wf-trait-fn-ret.stderr
+++ b/src/test/ui/wf/wf-trait-fn-ret.stderr
@@ -5,9 +5,12 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    |              -- required by this bound in `Bar`
 ...
 LL |     fn bar(&self) -> &Bar<Self>;
-   |                      ^^^^^^^^^^- help: consider further restricting `Self`: `where Self: std::cmp::Eq`
-   |                      |
-   |                      the trait `std::cmp::Eq` is not implemented for `Self`
+   |                      ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar(&self) -> &Bar<Self> where Self: std::cmp::Eq;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-fn-where-clause.stderr
index 2d6cf838f08..2d9ba56c585 100644
--- a/src/test/ui/wf/wf-trait-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-trait-fn-where-clause.stderr
@@ -5,9 +5,12 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    |              -- required by this bound in `Bar`
 ...
 LL |     fn bar(&self) where Self: Sized, Bar<Self>: Copy;
-   |                                                 ^^^^- help: consider further restricting `Self`: `, Self: std::cmp::Eq`
-   |                                                 |
-   |                                                 the trait `std::cmp::Eq` is not implemented for `Self`
+   |                                                 ^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar(&self) where Self: Sized, Bar<Self>: Copy, Self: std::cmp::Eq;
+   |                                                     ^^^^^^^^^^^^^^^^^^^^
 
 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 6de07d3e5cf..39baa6b8540 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -228,7 +228,6 @@ struct Builder {
     clippy_release: String,
     rustfmt_release: String,
     llvm_tools_release: String,
-    lldb_release: String,
     miri_release: String,
 
     input: PathBuf,
@@ -244,7 +243,6 @@ struct Builder {
     clippy_version: Option<String>,
     rustfmt_version: Option<String>,
     llvm_tools_version: Option<String>,
-    lldb_version: Option<String>,
     miri_version: Option<String>,
 
     rust_git_commit_hash: Option<String>,
@@ -253,7 +251,6 @@ struct Builder {
     clippy_git_commit_hash: Option<String>,
     rustfmt_git_commit_hash: Option<String>,
     llvm_tools_git_commit_hash: Option<String>,
-    lldb_git_commit_hash: Option<String>,
     miri_git_commit_hash: Option<String>,
 
     should_sign: bool,
@@ -284,7 +281,6 @@ fn main() {
     let miri_release = args.next().unwrap();
     let rustfmt_release = args.next().unwrap();
     let llvm_tools_release = args.next().unwrap();
-    let lldb_release = args.next().unwrap();
 
     // Do not ask for a passphrase while manually testing
     let mut passphrase = String::new();
@@ -300,7 +296,6 @@ fn main() {
         clippy_release,
         rustfmt_release,
         llvm_tools_release,
-        lldb_release,
         miri_release,
 
         input,
@@ -316,7 +311,6 @@ fn main() {
         clippy_version: None,
         rustfmt_version: None,
         llvm_tools_version: None,
-        lldb_version: None,
         miri_version: None,
 
         rust_git_commit_hash: None,
@@ -325,7 +319,6 @@ fn main() {
         clippy_git_commit_hash: None,
         rustfmt_git_commit_hash: None,
         llvm_tools_git_commit_hash: None,
-        lldb_git_commit_hash: None,
         miri_git_commit_hash: None,
 
         should_sign,
@@ -340,7 +333,6 @@ enum PkgType {
     Clippy,
     Rustfmt,
     LlvmTools,
-    Lldb,
     Miri,
     Other,
 }
@@ -355,7 +347,6 @@ impl PkgType {
             "clippy" | "clippy-preview" => Clippy,
             "rustfmt" | "rustfmt-preview" => Rustfmt,
             "llvm-tools" | "llvm-tools-preview" => LlvmTools,
-            "lldb" | "lldb-preview" => Lldb,
             "miri" | "miri-preview" => Miri,
             _ => Other,
         }
@@ -370,8 +361,6 @@ impl Builder {
         self.clippy_version = self.version("clippy", "x86_64-unknown-linux-gnu");
         self.rustfmt_version = self.version("rustfmt", "x86_64-unknown-linux-gnu");
         self.llvm_tools_version = self.version("llvm-tools", "x86_64-unknown-linux-gnu");
-        // lldb is only built for macOS.
-        self.lldb_version = self.version("lldb", "x86_64-apple-darwin");
         self.miri_version = self.version("miri", "x86_64-unknown-linux-gnu");
 
         self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu");
@@ -381,7 +370,6 @@ impl Builder {
         self.rustfmt_git_commit_hash = self.git_commit_hash("rustfmt", "x86_64-unknown-linux-gnu");
         self.llvm_tools_git_commit_hash =
             self.git_commit_hash("llvm-tools", "x86_64-unknown-linux-gnu");
-        self.lldb_git_commit_hash = self.git_commit_hash("lldb", "x86_64-unknown-linux-gnu");
         self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu");
 
         self.check_toolstate();
@@ -456,7 +444,6 @@ impl Builder {
         package("rustfmt-preview", HOSTS);
         package("rust-analysis", TARGETS);
         package("llvm-tools-preview", TARGETS);
-        package("lldb-preview", TARGETS);
     }
 
     fn add_profiles_to(&mut self, manifest: &mut Manifest) {
@@ -487,7 +474,6 @@ impl Builder {
                 "rls-preview",
                 "rust-src",
                 "llvm-tools-preview",
-                "lldb-preview",
                 "rust-analysis",
                 "miri-preview",
             ],
@@ -562,7 +548,6 @@ impl Builder {
             host_component("rls-preview"),
             host_component("rustfmt-preview"),
             host_component("llvm-tools-preview"),
-            host_component("lldb-preview"),
             host_component("rust-analysis"),
         ]);
 
@@ -692,7 +677,6 @@ impl Builder {
             Clippy => format!("clippy-{}-{}.tar.gz", self.clippy_release, target),
             Rustfmt => format!("rustfmt-{}-{}.tar.gz", self.rustfmt_release, target),
             LlvmTools => format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target),
-            Lldb => format!("lldb-{}-{}.tar.gz", self.lldb_release, target),
             Miri => format!("miri-{}-{}.tar.gz", self.miri_release, target),
             Other => format!("{}-{}-{}.tar.gz", component, self.rust_release, target),
         }
@@ -706,7 +690,6 @@ impl Builder {
             Clippy => &self.clippy_version,
             Rustfmt => &self.rustfmt_version,
             LlvmTools => &self.llvm_tools_version,
-            Lldb => &self.lldb_version,
             Miri => &self.miri_version,
             _ => &self.rust_version,
         }
@@ -720,7 +703,6 @@ impl Builder {
             Clippy => &self.clippy_git_commit_hash,
             Rustfmt => &self.rustfmt_git_commit_hash,
             LlvmTools => &self.llvm_tools_git_commit_hash,
-            Lldb => &self.lldb_git_commit_hash,
             Miri => &self.miri_git_commit_hash,
             _ => &self.rust_git_commit_hash,
         }
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 575773580c0..8457d6ad05c 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -1422,7 +1422,9 @@ Released 2018-09-13
 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
+[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
+[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 63ce2cd8cad..6999b6bd740 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -31,7 +31,6 @@ path = "src/driver.rs"
 # begin automatic update
 clippy_lints = { version = "0.0.212", path = "clippy_lints" }
 # end automatic update
-regex = "1"
 semver = "0.9"
 rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
 tempfile = { version = "3.1.0", optional = true }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 1f135cba6e4..51b5401da7d 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -247,6 +247,8 @@ mod literal_representation;
 mod loops;
 mod macro_use;
 mod main_recursion;
+mod manual_async_fn;
+mod manual_non_exhaustive;
 mod map_clone;
 mod map_unit_fn;
 mod match_on_vec_items;
@@ -628,6 +630,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &loops::WHILE_LET_ON_ITERATOR,
         &macro_use::MACRO_USE_IMPORTS,
         &main_recursion::MAIN_RECURSION,
+        &manual_async_fn::MANUAL_ASYNC_FN,
+        &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
         &map_clone::MAP_CLONE,
         &map_unit_fn::OPTION_MAP_UNIT_FN,
         &map_unit_fn::RESULT_MAP_UNIT_FN,
@@ -1054,7 +1058,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let max_struct_bools = conf.max_struct_bools;
     store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
     store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
-    store.register_late_pass(|| box wildcard_imports::WildcardImports);
+    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
+    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
     store.register_early_pass(|| box macro_use::MacroUseImports);
     store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
     store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
@@ -1064,6 +1069,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
     store.register_late_pass(|| box if_let_mutex::IfLetMutex);
     store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
+    store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
+    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1138,6 +1145,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
         LintId::of(&loops::EXPLICIT_ITER_LOOP),
         LintId::of(&macro_use::MACRO_USE_IMPORTS),
+        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&matches::MATCH_BOOL),
         LintId::of(&matches::SINGLE_MATCH_ELSE),
         LintId::of(&methods::FILTER_MAP),
@@ -1280,10 +1288,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::WHILE_LET_LOOP),
         LintId::of(&loops::WHILE_LET_ON_ITERATOR),
         LintId::of(&main_recursion::MAIN_RECURSION),
+        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
+        LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
         LintId::of(&map_clone::MAP_CLONE),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
         LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
-        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
         LintId::of(&matches::MATCH_AS_REF),
         LintId::of(&matches::MATCH_OVERLAPPING_ARM),
@@ -1474,6 +1483,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::NEEDLESS_RANGE_LOOP),
         LintId::of(&loops::WHILE_LET_ON_ITERATOR),
         LintId::of(&main_recursion::MAIN_RECURSION),
+        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
+        LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
         LintId::of(&map_clone::MAP_CLONE),
         LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
         LintId::of(&matches::MATCH_OVERLAPPING_ARM),
@@ -1647,7 +1658,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::NEVER_LOOP),
         LintId::of(&loops::REVERSE_RANGE_LOOP),
         LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
-        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
         LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
         LintId::of(&methods::CLONE_DOUBLE_REF),
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index f7c7fd82d83..2bbf4dba614 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -10,7 +10,6 @@ use crate::utils::{
 };
 use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg};
 use if_chain::if_chain;
-use itertools::Itertools;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
@@ -772,40 +771,48 @@ fn check_for_loop<'a, 'tcx>(
 
 fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId) -> bool {
     if_chain! {
-        if let ExprKind::Path(ref qpath) = expr.kind;
-        if let QPath::Resolved(None, ref path) = *qpath;
+        if let ExprKind::Path(qpath) = &expr.kind;
+        if let QPath::Resolved(None, path) = qpath;
         if path.segments.len() == 1;
         if let Res::Local(local_id) = qpath_res(cx, qpath, expr.hir_id);
-        // our variable!
-        if local_id == var;
         then {
-            return true;
+            // our variable!
+            local_id == var
+        } else {
+            false
         }
     }
+}
 
-    false
+#[derive(Clone, Copy)]
+enum OffsetSign {
+    Positive,
+    Negative,
 }
 
 struct Offset {
     value: String,
-    negate: bool,
+    sign: OffsetSign,
 }
 
 impl Offset {
-    fn negative(s: String) -> Self {
-        Self { value: s, negate: true }
+    fn negative(value: String) -> Self {
+        Self {
+            value,
+            sign: OffsetSign::Negative,
+        }
     }
 
-    fn positive(s: String) -> Self {
+    fn positive(value: String) -> Self {
         Self {
-            value: s,
-            negate: false,
+            value,
+            sign: OffsetSign::Positive,
         }
     }
 }
 
-struct FixedOffsetVar {
-    var_name: String,
+struct FixedOffsetVar<'hir> {
+    var: &'hir Expr<'hir>,
     offset: Offset,
 }
 
@@ -819,10 +826,20 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'_>) -> bool {
     is_slice || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
 }
 
-fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId) -> Option<FixedOffsetVar> {
+fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    if_chain! {
+        if let ExprKind::MethodCall(method, _, args) = expr.kind;
+        if method.ident.name == sym!(clone);
+        if args.len() == 1;
+        if let Some(arg) = args.get(0);
+        then { arg } else { expr }
+    }
+}
+
+fn get_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, idx: &Expr<'_>, var: HirId) -> Option<Offset> {
     fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr<'_>, var: HirId) -> Option<String> {
-        match e.kind {
-            ExprKind::Lit(ref l) => match l.node {
+        match &e.kind {
+            ExprKind::Lit(l) => match l.node {
                 ast::LitKind::Int(x, _ty) => Some(x.to_string()),
                 _ => None,
             },
@@ -831,115 +848,139 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, v
         }
     }
 
-    if let ExprKind::Index(ref seqexpr, ref idx) = expr.kind {
-        let ty = cx.tables.expr_ty(seqexpr);
-        if !is_slice_like(cx, ty) {
-            return None;
-        }
-
-        let offset = match idx.kind {
-            ExprKind::Binary(op, ref lhs, ref rhs) => match op.node {
-                BinOpKind::Add => {
-                    let offset_opt = if same_var(cx, lhs, var) {
-                        extract_offset(cx, rhs, var)
-                    } else if same_var(cx, rhs, var) {
-                        extract_offset(cx, lhs, var)
-                    } else {
-                        None
-                    };
-
-                    offset_opt.map(Offset::positive)
-                },
-                BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
-                _ => None,
-            },
-            ExprKind::Path(..) => {
-                if same_var(cx, idx, var) {
-                    Some(Offset::positive("0".into()))
+    match idx.kind {
+        ExprKind::Binary(op, lhs, rhs) => match op.node {
+            BinOpKind::Add => {
+                let offset_opt = if same_var(cx, lhs, var) {
+                    extract_offset(cx, rhs, var)
+                } else if same_var(cx, rhs, var) {
+                    extract_offset(cx, lhs, var)
                 } else {
                     None
-                }
+                };
+
+                offset_opt.map(Offset::positive)
             },
+            BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
             _ => None,
-        };
-
-        offset.map(|o| FixedOffsetVar {
-            var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
-            offset: o,
-        })
-    } else {
-        None
-    }
-}
-
-fn fetch_cloned_fixed_offset_var<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &Expr<'_>,
-    var: HirId,
-) -> Option<FixedOffsetVar> {
-    if_chain! {
-        if let ExprKind::MethodCall(ref method, _, ref args) = expr.kind;
-        if method.ident.name == sym!(clone);
-        if args.len() == 1;
-        if let Some(arg) = args.get(0);
-        then {
-            return get_fixed_offset_var(cx, arg, var);
-        }
+        },
+        ExprKind::Path(..) if same_var(cx, idx, var) => Some(Offset::positive("0".into())),
+        _ => None,
     }
-
-    get_fixed_offset_var(cx, expr, var)
 }
 
-fn get_indexed_assignments<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    body: &Expr<'_>,
-    var: HirId,
-) -> Vec<(FixedOffsetVar, FixedOffsetVar)> {
-    fn get_assignment<'a, 'tcx>(
-        cx: &LateContext<'a, 'tcx>,
-        e: &Expr<'_>,
-        var: HirId,
-    ) -> Option<(FixedOffsetVar, FixedOffsetVar)> {
-        if let ExprKind::Assign(ref lhs, ref rhs, _) = e.kind {
-            match (
-                get_fixed_offset_var(cx, lhs, var),
-                fetch_cloned_fixed_offset_var(cx, rhs, var),
-            ) {
-                (Some(offset_left), Some(offset_right)) => {
-                    // Source and destination must be different
-                    if offset_left.var_name == offset_right.var_name {
-                        None
-                    } else {
-                        Some((offset_left, offset_right))
-                    }
-                },
-                _ => None,
-            }
+fn get_assignments<'tcx>(body: &'tcx Expr<'tcx>) -> impl Iterator<Item = Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>> {
+    fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+        if let ExprKind::Assign(lhs, rhs, _) = e.kind {
+            Some((lhs, rhs))
         } else {
             None
         }
     }
 
-    if let ExprKind::Block(ref b, _) = body.kind {
-        let Block {
-            ref stmts, ref expr, ..
-        } = **b;
+    // This is one of few ways to return different iterators
+    // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434
+    let mut iter_a = None;
+    let mut iter_b = None;
+
+    if let ExprKind::Block(b, _) = body.kind {
+        let Block { stmts, expr, .. } = *b;
 
-        stmts
+        iter_a = stmts
             .iter()
-            .map(|stmt| match stmt.kind {
+            .filter_map(|stmt| match stmt.kind {
                 StmtKind::Local(..) | StmtKind::Item(..) => None,
-                StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => Some(get_assignment(cx, e, var)),
+                StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e),
             })
-            .chain(expr.as_ref().into_iter().map(|e| Some(get_assignment(cx, &*e, var))))
-            .filter_map(|op| op)
-            .collect::<Option<Vec<_>>>()
-            .unwrap_or_default()
+            .chain(expr.into_iter())
+            .map(get_assignment)
+            .into()
     } else {
-        get_assignment(cx, body, var).into_iter().collect()
+        iter_b = Some(get_assignment(body))
     }
+
+    iter_a.into_iter().flatten().chain(iter_b.into_iter())
 }
 
+fn build_manual_memcpy_suggestion<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    start: &Expr<'_>,
+    end: &Expr<'_>,
+    limits: ast::RangeLimits,
+    dst_var: FixedOffsetVar<'_>,
+    src_var: FixedOffsetVar<'_>,
+) -> String {
+    fn print_sum(arg1: &str, arg2: &Offset) -> String {
+        match (arg1, &arg2.value[..], arg2.sign) {
+            ("0", "0", _) => "0".into(),
+            ("0", x, OffsetSign::Positive) | (x, "0", _) => x.into(),
+            ("0", x, OffsetSign::Negative) => format!("-{}", x),
+            (x, y, OffsetSign::Positive) => format!("({} + {})", x, y),
+            (x, y, OffsetSign::Negative) => {
+                if x == y {
+                    "0".into()
+                } else {
+                    format!("({} - {})", x, y)
+                }
+            },
+        }
+    }
+
+    fn print_offset(start_str: &str, inline_offset: &Offset) -> String {
+        let offset = print_sum(start_str, inline_offset);
+        if offset.as_str() == "0" {
+            "".into()
+        } else {
+            offset
+        }
+    }
+
+    let print_limit = |end: &Expr<'_>, offset: Offset, var: &Expr<'_>| {
+        if_chain! {
+            if let ExprKind::MethodCall(method, _, len_args) = end.kind;
+            if method.ident.name == sym!(len);
+            if len_args.len() == 1;
+            if let Some(arg) = len_args.get(0);
+            if var_def_id(cx, arg) == var_def_id(cx, var);
+            then {
+                match offset.sign {
+                    OffsetSign::Negative => format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value),
+                    OffsetSign::Positive => "".into(),
+                }
+            } else {
+                let end_str = match limits {
+                    ast::RangeLimits::Closed => {
+                        let end = sugg::Sugg::hir(cx, end, "<count>");
+                        format!("{}", end + sugg::ONE)
+                    },
+                    ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
+                };
+
+                print_sum(&end_str, &offset)
+            }
+        }
+    };
+
+    let start_str = snippet(cx, start.span, "").to_string();
+    let dst_offset = print_offset(&start_str, &dst_var.offset);
+    let dst_limit = print_limit(end, dst_var.offset, dst_var.var);
+    let src_offset = print_offset(&start_str, &src_var.offset);
+    let src_limit = print_limit(end, src_var.offset, src_var.var);
+
+    let dst_var_name = snippet_opt(cx, dst_var.var.span).unwrap_or_else(|| "???".into());
+    let src_var_name = snippet_opt(cx, src_var.var.span).unwrap_or_else(|| "???".into());
+
+    let dst = if dst_offset == "" && dst_limit == "" {
+        dst_var_name
+    } else {
+        format!("{}[{}..{}]", dst_var_name, dst_offset, dst_limit)
+    };
+
+    format!(
+        "{}.clone_from_slice(&{}[{}..{}])",
+        dst, src_var_name, src_offset, src_limit
+    )
+}
 /// Checks for for loops that sequentially copy items from one slice-like
 /// object to another.
 fn detect_manual_memcpy<'a, 'tcx>(
@@ -951,93 +992,43 @@ fn detect_manual_memcpy<'a, 'tcx>(
 ) {
     if let Some(higher::Range {
         start: Some(start),
-        ref end,
+        end: Some(end),
         limits,
     }) = higher::range(cx, arg)
     {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
-            let print_sum = |arg1: &Offset, arg2: &Offset| -> String {
-                match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) {
-                    ("0", _, "0", _) => "".into(),
-                    ("0", _, x, false) | (x, false, "0", false) => x.into(),
-                    ("0", _, x, true) | (x, false, "0", true) => format!("-{}", x),
-                    (x, false, y, false) => format!("({} + {})", x, y),
-                    (x, false, y, true) => {
-                        if x == y {
-                            "0".into()
-                        } else {
-                            format!("({} - {})", x, y)
-                        }
-                    },
-                    (x, true, y, false) => {
-                        if x == y {
-                            "0".into()
-                        } else {
-                            format!("({} - {})", y, x)
-                        }
-                    },
-                    (x, true, y, true) => format!("-({} + {})", x, y),
-                }
-            };
-
-            let print_limit = |end: &Option<&Expr<'_>>, offset: Offset, var_name: &str| {
-                if let Some(end) = *end {
-                    if_chain! {
-                        if let ExprKind::MethodCall(ref method, _, ref len_args) = end.kind;
-                        if method.ident.name == sym!(len);
-                        if len_args.len() == 1;
-                        if let Some(arg) = len_args.get(0);
-                        if snippet(cx, arg.span, "??") == var_name;
-                        then {
-                            return if offset.negate {
-                                format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
-                            } else {
-                                String::new()
-                            };
-                        }
-                    }
-
-                    let end_str = match limits {
-                        ast::RangeLimits::Closed => {
-                            let end = sugg::Sugg::hir(cx, end, "<count>");
-                            format!("{}", end + sugg::ONE)
-                        },
-                        ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
-                    };
-
-                    print_sum(&Offset::positive(end_str), &offset)
-                } else {
-                    "..".into()
-                }
-            };
-
             // The only statements in the for loops can be indexed assignments from
             // indexed retrievals.
-            let manual_copies = get_indexed_assignments(cx, body, canonical_id);
-
-            let big_sugg = manual_copies
-                .into_iter()
-                .map(|(dst_var, src_var)| {
-                    let start_str = Offset::positive(snippet(cx, start.span, "").to_string());
-                    let dst_offset = print_sum(&start_str, &dst_var.offset);
-                    let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name);
-                    let src_offset = print_sum(&start_str, &src_var.offset);
-                    let src_limit = print_limit(end, src_var.offset, &src_var.var_name);
-                    let dst = if dst_offset == "" && dst_limit == "" {
-                        dst_var.var_name
-                    } else {
-                        format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit)
-                    };
-
-                    format!(
-                        "{}.clone_from_slice(&{}[{}..{}])",
-                        dst, src_var.var_name, src_offset, src_limit
-                    )
+            let big_sugg = get_assignments(body)
+                .map(|o| {
+                    o.and_then(|(lhs, rhs)| {
+                        let rhs = fetch_cloned_expr(rhs);
+                        if_chain! {
+                            if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind;
+                            if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind;
+                            if is_slice_like(cx, cx.tables.expr_ty(seqexpr_left))
+                                && is_slice_like(cx, cx.tables.expr_ty(seqexpr_right));
+                            if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id);
+                            if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id);
+
+                            // Source and destination must be different
+                            if var_def_id(cx, seqexpr_left) != var_def_id(cx, seqexpr_right);
+                            then {
+                                Some((FixedOffsetVar { var: seqexpr_left, offset: offset_left },
+                                    FixedOffsetVar { var: seqexpr_right, offset: offset_right }))
+                            } else {
+                                None
+                            }
+                        }
+                    })
                 })
-                .join("\n    ");
+                .map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, dst, src)))
+                .collect::<Option<Vec<_>>>()
+                .filter(|v| !v.is_empty())
+                .map(|v| v.join("\n    "));
 
-            if !big_sugg.is_empty() {
+            if let Some(big_sugg) = big_sugg {
                 span_lint_and_sugg(
                     cx,
                     MANUAL_MEMCPY,
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
new file mode 100644
index 00000000000..cb72a240582
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -0,0 +1,159 @@
+use crate::utils::paths::FUTURE_FROM_GENERATOR;
+use crate::utils::{match_function_call, snippet_block, snippet_opt, span_lint_and_then};
+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,
+};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** It checks for manual implementations of `async` functions.
+    ///
+    /// **Why is this bad?** It's more idiomatic to use the dedicated syntax.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// use std::future::Future;
+    ///
+    /// fn foo() -> impl Future<Output = i32> { async { 42 } }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::future::Future;
+    ///
+    /// async fn foo() -> i32 { 42 }
+    /// ```
+    pub MANUAL_ASYNC_FN,
+    style,
+    "manual implementations of `async` functions can be simplified using the dedicated syntax"
+}
+
+declare_lint_pass!(ManualAsyncFn => [MANUAL_ASYNC_FN]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ManualAsyncFn {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        span: Span,
+        _: HirId,
+    ) {
+        if_chain! {
+            if let Some(header) = kind.header();
+            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(output) = future_output_ty(trait_ref);
+            // 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();
+            if let Some(closure_body) = desugared_async_block(cx, block);
+            then {
+                let header_span = span.with_hi(ret_ty.span.hi());
+
+                span_lint_and_then(
+                    cx,
+                    MANUAL_ASYNC_FN,
+                    header_span,
+                    "this function can be simplified using the `async fn` syntax",
+                    |diag| {
+                        if_chain! {
+                            if let Some(header_snip) = snippet_opt(cx, header_span);
+                            if let Some(ret_pos) = header_snip.rfind("->");
+                            if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
+                            then {
+                                let help = format!("make the function `async` and {}", ret_sugg);
+                                diag.span_suggestion(
+                                    header_span,
+                                    &help,
+                                    format!("async {}{}", &header_snip[..ret_pos], ret_snip),
+                                    Applicability::MachineApplicable
+                                );
+
+                                let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
+                                diag.span_suggestion(
+                                    block.span,
+                                    "move the body of the async block to the enclosing function",
+                                    body_snip.to_string(),
+                                    Applicability::MachineApplicable
+                                );
+                            }
+                        }
+                    },
+                );
+            }
+        }
+    }
+}
+
+fn future_trait_ref<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &'tcx Ty<'tcx>) -> Option<&'tcx TraitRef<'tcx>> {
+    if_chain! {
+        if let TyKind::Def(item_id, _) = 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();
+        then {
+            return Some(&poly.trait_ref);
+        }
+    }
+
+    None
+}
+
+fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
+    if_chain! {
+        if let Some(segment) = trait_ref.path.segments.last();
+        if let Some(args) = segment.args;
+        if args.bindings.len() == 1;
+        let binding = &args.bindings[0];
+        if binding.ident.as_str() == "Output";
+        if let TypeBindingKind::Equality{ty: output} = binding.kind;
+        then {
+            return Some(output)
+        }
+    }
+
+    None
+}
+
+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;
+        if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
+        if args.len() == 1;
+        if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0];
+        let closure_body = cx.tcx.hir().body(body_id);
+        if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind;
+        then {
+            return Some(closure_body);
+        }
+    }
+
+    None
+}
+
+fn suggested_ret(cx: &LateContext<'_, '_>, output: &Ty<'_>) -> Option<(&'static str, String)> {
+    match output.kind {
+        TyKind::Tup(tys) if tys.is_empty() => {
+            let sugg = "remove the return type";
+            Some((sugg, "".into()))
+        },
+        _ => {
+            let sugg = "return the output of the future directly";
+            snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip)))
+        },
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
new file mode 100644
index 00000000000..f3b8902e26f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -0,0 +1,173 @@
+use crate::utils::{snippet_opt, span_lint_and_then};
+use if_chain::if_chain;
+use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind};
+use rustc_attr as attr;
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
+    ///
+    /// **Why is this bad?** Using the #[non_exhaustive] attribute expresses better the intent
+    /// and allows possible optimizations when applied to enums.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// struct S {
+    ///     pub a: i32,
+    ///     pub b: i32,
+    ///     _c: (),
+    /// }
+    ///
+    /// enum E {
+    ///     A,
+    ///     B,
+    ///     #[doc(hidden)]
+    ///     _C,
+    /// }
+    ///
+    /// struct T(pub i32, pub i32, ());
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #[non_exhaustive]
+    /// struct S {
+    ///     pub a: i32,
+    ///     pub b: i32,
+    /// }
+    ///
+    /// #[non_exhaustive]
+    /// enum E {
+    ///     A,
+    ///     B,
+    /// }
+    ///
+    /// #[non_exhaustive]
+    /// struct T(pub i32, pub i32);
+    /// ```
+    pub MANUAL_NON_EXHAUSTIVE,
+    style,
+    "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
+}
+
+declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
+
+impl EarlyLintPass for ManualNonExhaustive {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        match &item.kind {
+            ItemKind::Enum(def, _) => {
+                check_manual_non_exhaustive_enum(cx, item, &def.variants);
+            },
+            ItemKind::Struct(variant_data, _) => {
+                if let VariantData::Unit(..) = variant_data {
+                    return;
+                }
+
+                check_manual_non_exhaustive_struct(cx, item, variant_data);
+            },
+            _ => {},
+        }
+    }
+}
+
+fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) {
+    fn is_non_exhaustive_marker(variant: &Variant) -> bool {
+        matches!(variant.data, VariantData::Unit(_))
+            && variant.ident.as_str().starts_with('_')
+            && variant.attrs.iter().any(|a| is_doc_hidden(a))
+    }
+
+    fn is_doc_hidden(attr: &Attribute) -> bool {
+        attr.check_name(sym!(doc))
+            && match attr.meta_item_list() {
+                Some(l) => attr::list_contains_name(&l, sym!(hidden)),
+                None => false,
+            }
+    }
+
+    if_chain! {
+        let mut markers = variants.iter().filter(|v| is_non_exhaustive_marker(v));
+        if let Some(marker) = markers.next();
+        if markers.count() == 0 && variants.len() > 1;
+        then {
+            span_lint_and_then(
+                cx,
+                MANUAL_NON_EXHAUSTIVE,
+                item.span,
+                "this seems like a manual implementation of the non-exhaustive pattern",
+                |diag| {
+                    if_chain! {
+                        if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+                        let header_span = cx.sess.source_map().span_until_char(item.span, '{');
+                        if let Some(snippet) = snippet_opt(cx, header_span);
+                        then {
+                            diag.span_suggestion(
+                                header_span,
+                                "add the attribute",
+                                format!("#[non_exhaustive] {}", snippet),
+                                Applicability::Unspecified,
+                            );
+                        }
+                    }
+                    diag.span_help(marker.span, "remove this variant");
+                });
+        }
+    }
+}
+
+fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) {
+    fn is_private(field: &StructField) -> bool {
+        matches!(field.vis.node, VisibilityKind::Inherited)
+    }
+
+    fn is_non_exhaustive_marker(field: &StructField) -> bool {
+        is_private(field) && field.ty.kind.is_unit() && field.ident.map_or(true, |n| n.as_str().starts_with('_'))
+    }
+
+    fn find_header_span(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) -> Span {
+        let delimiter = match data {
+            VariantData::Struct(..) => '{',
+            VariantData::Tuple(..) => '(',
+            VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"),
+        };
+
+        cx.sess.source_map().span_until_char(item.span, delimiter)
+    }
+
+    let fields = data.fields();
+    let private_fields = fields.iter().filter(|f| is_private(f)).count();
+    let public_fields = fields.iter().filter(|f| f.vis.node.is_pub()).count();
+
+    if_chain! {
+        if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1;
+        if let Some(marker) = fields.iter().find(|f| is_non_exhaustive_marker(f));
+        then {
+            span_lint_and_then(
+                cx,
+                MANUAL_NON_EXHAUSTIVE,
+                item.span,
+                "this seems like a manual implementation of the non-exhaustive pattern",
+                |diag| {
+                    if_chain! {
+                        if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+                        let header_span = find_header_span(cx, item, data);
+                        if let Some(snippet) = snippet_opt(cx, header_span);
+                        then {
+                            diag.span_suggestion(
+                                header_span,
+                                "add the attribute",
+                                format!("#[non_exhaustive] {}", snippet),
+                                Applicability::Unspecified,
+                            );
+                        }
+                    }
+                    diag.span_help(marker.span, "remove this field");
+                });
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
index 4071406cc84..ee69628e9f0 100644
--- a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{self, is_type_diagnostic_item, match_type, snippet, span_lint_and_sugg, walk_ptrs_ty};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, MatchSource};
@@ -38,7 +38,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     pub MATCH_ON_VEC_ITEMS,
-    correctness,
+    pedantic,
     "matching on vector elements can panic"
 }
 
@@ -75,10 +75,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchOnVecItems {
 
 fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::Index(ref array, _) = expr.kind;
-        let ty = cx.tables.expr_ty(array);
-        let ty = walk_ptrs_ty(ty);
-        if is_type_diagnostic_item(cx, ty, sym!(vec_type));
+        if let ExprKind::Index(ref array, ref index) = expr.kind;
+        if is_vector(cx, array);
+        if !is_full_range(cx, index);
 
         then {
             return Some(expr);
@@ -87,3 +86,15 @@ fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>)
 
     None
 }
+
+fn is_vector(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.tables.expr_ty(expr);
+    let ty = walk_ptrs_ty(ty);
+    is_type_diagnostic_item(cx, ty, sym!(vec_type))
+}
+
+fn is_full_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.tables.expr_ty(expr);
+    let ty = walk_ptrs_ty(ty);
+    match_type(cx, ty, &utils::paths::RANGE_FULL)
+}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early.rs b/src/tools/clippy/clippy_lints/src/misc_early.rs
index adfd8dfb1c1..62ee051624b 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early.rs
@@ -24,8 +24,25 @@ declare_clippy_lint! {
     /// **Known problems:** None.
     ///
     /// **Example:**
-    /// ```ignore
-    /// let { a: _, b: ref b, c: _ } = ..
+    /// ```rust
+    /// # struct Foo {
+    /// #     a: i32,
+    /// #     b: i32,
+    /// #     c: i32,
+    /// # }
+    /// let f = Foo { a: 0, b: 0, c: 0 };
+    ///
+    /// // Bad
+    /// match f {
+    ///     Foo { a: _, b: 0, .. } => {},
+    ///     Foo { a: _, b: _, c: _ } => {},
+    /// }
+    ///
+    /// // Good
+    /// match f {
+    ///     Foo { b: 0, .. } => {},
+    ///     Foo { .. } => {},
+    /// }
     /// ```
     pub UNNEEDED_FIELD_PATTERN,
     restriction,
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 5235c98efab..f3844c7d3b6 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -1,4 +1,7 @@
-use crate::utils::{higher::if_block, is_type_diagnostic_item, span_lint_and_then, usage::is_potentially_mutated};
+use crate::utils::{
+    differing_macro_contexts, higher::if_block, is_type_diagnostic_item, span_lint_and_then,
+    usage::is_potentially_mutated,
+};
 use if_chain::if_chain;
 use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp};
@@ -73,6 +76,8 @@ struct UnwrapInfo<'tcx> {
     ident: &'tcx Path<'tcx>,
     /// The check, like `x.is_ok()`
     check: &'tcx Expr<'tcx>,
+    /// The branch where the check takes place, like `if x.is_ok() { .. }`
+    branch: &'tcx Expr<'tcx>,
     /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
     safe_to_unwrap: bool,
 }
@@ -82,19 +87,20 @@ struct UnwrapInfo<'tcx> {
 fn collect_unwrap_info<'a, 'tcx>(
     cx: &'a LateContext<'a, 'tcx>,
     expr: &'tcx Expr<'_>,
+    branch: &'tcx Expr<'_>,
     invert: bool,
 ) -> Vec<UnwrapInfo<'tcx>> {
     if let ExprKind::Binary(op, left, right) = &expr.kind {
         match (invert, op.node) {
             (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => {
-                let mut unwrap_info = collect_unwrap_info(cx, left, invert);
-                unwrap_info.append(&mut collect_unwrap_info(cx, right, invert));
+                let mut unwrap_info = collect_unwrap_info(cx, left, branch, invert);
+                unwrap_info.append(&mut collect_unwrap_info(cx, right, branch, invert));
                 return unwrap_info;
             },
             _ => (),
         }
     } else if let ExprKind::Unary(UnOp::UnNot, expr) = &expr.kind {
-        return collect_unwrap_info(cx, expr, !invert);
+        return collect_unwrap_info(cx, expr, branch, !invert);
     } else {
         if_chain! {
             if let ExprKind::MethodCall(method_name, _, args) = &expr.kind;
@@ -111,7 +117,7 @@ fn collect_unwrap_info<'a, 'tcx>(
                     _ => unreachable!(),
                 };
                 let safe_to_unwrap = unwrappable != invert;
-                return vec![UnwrapInfo { ident: path, check: expr, safe_to_unwrap }];
+                return vec![UnwrapInfo { ident: path, check: expr, branch, safe_to_unwrap }];
             }
         }
     }
@@ -121,7 +127,7 @@ fn collect_unwrap_info<'a, 'tcx>(
 impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
     fn visit_branch(&mut self, cond: &'tcx Expr<'_>, branch: &'tcx Expr<'_>, else_branch: bool) {
         let prev_len = self.unwrappables.len();
-        for unwrap_info in collect_unwrap_info(self.cx, cond, else_branch) {
+        for unwrap_info in collect_unwrap_info(self.cx, cond, branch, else_branch) {
             if is_potentially_mutated(unwrap_info.ident, cond, self.cx)
                 || is_potentially_mutated(unwrap_info.ident, branch, self.cx)
             {
@@ -158,6 +164,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
                 let call_to_unwrap = method_name.ident.name == sym!(unwrap);
                 if let Some(unwrappable) = self.unwrappables.iter()
                     .find(|u| u.ident.res == path.res);
+                // Span contexts should not differ with the conditional branch
+                if !differing_macro_contexts(unwrappable.branch.span, expr.span);
+                if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span);
                 then {
                     if call_to_unwrap == unwrappable.safe_to_unwrap {
                         span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 4b81ff33495..57b9eafd14d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -158,6 +158,8 @@ define_Conf! {
     (max_struct_bools, "max_struct_bools": u64, 3),
     /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have
     (max_fn_params_bools, "max_fn_params_bools": u64, 3),
+    /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
+    (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
 }
 
 impl Default for Conf {
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 2fd080e9ef0..438a9f42ccd 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -40,15 +40,12 @@ use rustc_hir::{
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::traits;
 use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 use rustc_target::abi::Integer;
-use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use smallvec::SmallVec;
 
@@ -326,19 +323,8 @@ pub fn implements_trait<'a, 'tcx>(
     trait_id: DefId,
     ty_params: &[GenericArg<'tcx>],
 ) -> bool {
-    let ty = cx.tcx.erase_regions(&ty);
-    let obligation = predicate_for_trait_def(
-        cx.tcx,
-        cx.param_env,
-        traits::ObligationCause::dummy(),
-        trait_id,
-        0,
-        ty,
-        ty_params,
-    );
-    cx.tcx
-        .infer_ctxt()
-        .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+    let ty_params = cx.tcx.mk_substs(ty_params.iter());
+    cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
 }
 
 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.
@@ -933,6 +919,7 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_, '_>, expr: &Exp
 }
 
 /// Returns `true` if a pattern is refutable.
+// TODO: should be implemented using rustc/mir_build/hair machinery
 pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat<'_>) -> bool {
     fn is_enum_variant(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, id: HirId) -> bool {
         matches!(
@@ -946,27 +933,34 @@ pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat<'_>) -> bool {
     }
 
     match pat.kind {
-        PatKind::Binding(..) | PatKind::Wild => false,
+        PatKind::Wild => false,
+        PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
         PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
         PatKind::Lit(..) | PatKind::Range(..) => true,
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
-        PatKind::Or(ref pats) | PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+        PatKind::Or(ref pats) => {
+            // TODO: should be the honest check, that pats is exhaustive set
+            are_refutable(cx, pats.iter().map(|pat| &**pat))
+        },
+        PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
         PatKind::Struct(ref qpath, ref fields, _) => {
-            if is_enum_variant(cx, qpath, pat.hir_id) {
-                true
-            } else {
-                are_refutable(cx, fields.iter().map(|field| &*field.pat))
-            }
+            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
         },
         PatKind::TupleStruct(ref qpath, ref pats, _) => {
-            if is_enum_variant(cx, qpath, pat.hir_id) {
-                true
-            } else {
-                are_refutable(cx, pats.iter().map(|pat| &**pat))
-            }
+            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
         PatKind::Slice(ref head, ref middle, ref tail) => {
-            are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat))
+            match &cx.tables.node_type(pat.hir_id).kind {
+                ty::Slice(..) => {
+                    // [..] is the only irrefutable slice pattern.
+                    !head.is_empty() || middle.is_none() || !tail.is_empty()
+                },
+                ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)),
+                _ => {
+                    // unreachable!()
+                    true
+                },
+            }
         },
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index ca2c4ade155..b3ad2ad9d99 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -42,6 +42,7 @@ pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments
 pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
 pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
+pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
 pub const HASH: [&str; 2] = ["hash", "Hash"];
 pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
 pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
@@ -85,7 +86,7 @@ pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
 pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
 pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
-pub const RANGE_FULL: [&str; 3] = ["core", "ops", "RangeFull"];
+pub const RANGE_FULL: [&str; 4] = ["core", "ops", "range", "RangeFull"];
 pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
 pub const RANGE_INCLUSIVE_NEW: [&str; 4] = ["core", "ops", "RangeInclusive", "new"];
 pub const RANGE_INCLUSIVE_STD_NEW: [&str; 4] = ["std", "ops", "RangeInclusive", "new"];
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index f3038861cee..32d9a45c37d 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -3,10 +3,10 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{
     def::{DefKind, Res},
-    Item, ItemKind, UseKind,
+    Item, ItemKind, PathSegment, UseKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::BytePos;
 
 declare_clippy_lint! {
@@ -43,9 +43,14 @@ declare_clippy_lint! {
     ///
     /// This can lead to confusing error messages at best and to unexpected behavior at worst.
     ///
-    /// Note that this will not warn about wildcard imports from modules named `prelude`; many
-    /// crates (including the standard library) provide modules named "prelude" specifically
-    /// designed for wildcard import.
+    /// **Exceptions:**
+    ///
+    /// Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
+    /// provide modules named "prelude" specifically designed for wildcard import.
+    ///
+    /// `use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
+    ///
+    /// These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
     ///
     /// **Known problems:** If macros are imported through the wildcard, this macro is not included
     /// by the suggestion and has to be added by hand.
@@ -73,18 +78,34 @@ declare_clippy_lint! {
     "lint `use _::*` statements"
 }
 
-declare_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
+#[derive(Default)]
+pub struct WildcardImports {
+    warn_on_all: bool,
+    test_modules_deep: u32,
+}
+
+impl WildcardImports {
+    pub fn new(warn_on_all: bool) -> Self {
+        Self {
+            warn_on_all,
+            test_modules_deep: 0,
+        }
+    }
+}
+
+impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
 
 impl LateLintPass<'_, '_> for WildcardImports {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) {
+        if is_test_module_or_function(item) {
+            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
+        }
         if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
             return;
         }
         if_chain! {
-            if !in_macro(item.span);
             if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
-            // don't lint prelude glob imports
-            if !use_path.segments.iter().last().map_or(false, |ps| ps.ident.as_str() == "prelude");
+            if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
             let used_imports = cx.tcx.names_imported_by_glob_use(item.hir_id.owner);
             if !used_imports.is_empty(); // Already handled by `unused_imports`
             then {
@@ -109,8 +130,7 @@ impl LateLintPass<'_, '_> for WildcardImports {
                         span = use_path.span.with_hi(item.span.hi() - BytePos(1));
                     }
                     (
-                        span,
-                        false,
+                        span, false,
                     )
                 };
 
@@ -153,4 +173,36 @@ impl LateLintPass<'_, '_> for WildcardImports {
             }
         }
     }
+
+    fn check_item_post(&mut self, _: &LateContext<'_, '_>, item: &Item<'_>) {
+        if is_test_module_or_function(item) {
+            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
+        }
+    }
+}
+
+impl WildcardImports {
+    fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
+        in_macro(item.span)
+            || is_prelude_import(segments)
+            || (is_super_only_import(segments) && self.test_modules_deep > 0)
+    }
+}
+
+// Allow "...prelude::*" imports.
+// Many crates have a prelude, and it is imported as a glob by design.
+fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool {
+    segments
+        .iter()
+        .last()
+        .map_or(false, |ps| ps.ident.as_str() == "prelude")
+}
+
+// Allow "super::*" imports in tests.
+fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool {
+    segments.len() == 1 && segments[0].ident.as_str() == "super"
+}
+
+fn is_test_module_or_function(item: &Item<'_>) -> bool {
+    matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
 }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 5ad43ad55a3..26bf463bd29 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -483,8 +483,8 @@ fn check_newlines(fmtstr: &StrLit) -> bool {
     };
 
     match fmtstr.style {
-        StrStyle::Cooked => unescape::unescape_str(contents, &mut cb),
-        StrStyle::Raw(_) => unescape::unescape_raw_str(contents, &mut cb),
+        StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb),
+        StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb),
     }
 
     should_lint
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 2c699998ea9..1ce0300f239 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -296,7 +296,7 @@ pub fn main() {
     rustc_driver::init_rustc_env_logger();
     lazy_static::initialize(&ICE_HOOK);
     exit(
-        rustc_driver::catch_fatal_errors(move || {
+        rustc_driver::catch_with_exit_code(move || {
             let mut orig_args: Vec<String> = env::args().collect();
 
             if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -411,7 +411,5 @@ pub fn main() {
                 if clippy_enabled { &mut clippy } else { &mut default };
             rustc_driver::run_compiler(&args, callbacks, None, None)
         })
-        .and_then(|result| result)
-        .is_err() as i32,
     )
 }
diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs
index 72675c25175..51d1cb2216a 100644
--- a/src/tools/clippy/src/lintlist/mod.rs
+++ b/src/tools/clippy/src/lintlist/mod.rs
@@ -1082,6 +1082,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "main_recursion",
     },
     Lint {
+        name: "manual_async_fn",
+        group: "style",
+        desc: "manual implementations of `async` functions can be simplified using the dedicated syntax",
+        deprecation: None,
+        module: "manual_async_fn",
+    },
+    Lint {
         name: "manual_memcpy",
         group: "perf",
         desc: "manually copying items between slices",
@@ -1089,6 +1096,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "loops",
     },
     Lint {
+        name: "manual_non_exhaustive",
+        group: "style",
+        desc: "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]",
+        deprecation: None,
+        module: "manual_non_exhaustive",
+    },
+    Lint {
         name: "manual_saturating_arithmetic",
         group: "style",
         desc: "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`",
@@ -1146,7 +1160,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "match_on_vec_items",
-        group: "correctness",
+        group: "pedantic",
         desc: "matching on vector elements can panic",
         deprecation: None,
         module: "match_on_vec_items",
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 18f5d994ba8..53970af4107 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-struct-bools`, `max-fn-params-bools`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/builtin-type-shadow.stderr b/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
index b6a4adde848..bc785b075e0 100644
--- a/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
+++ b/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
@@ -18,8 +18,6 @@ LL |     42
    |
    = note: expected type parameter `u32`
                         found type `{integer}`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
index b0fc26ff76d..3e7b4b390ba 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -9,6 +9,30 @@ macro_rules! m {
     };
 }
 
+macro_rules! checks_in_param {
+    ($a:expr, $b:expr) => {
+        if $a {
+            $b;
+        }
+    };
+}
+
+macro_rules! checks_unwrap {
+    ($a:expr, $b:expr) => {
+        if $a.is_some() {
+            $b;
+        }
+    };
+}
+
+macro_rules! checks_some {
+    ($a:expr, $b:expr) => {
+        if $a {
+            $b.unwrap();
+        }
+    };
+}
+
 fn main() {
     let x = Some(());
     if x.is_some() {
@@ -22,6 +46,9 @@ fn main() {
         x.unwrap(); // unnecessary
     }
     m!(x);
+    checks_in_param!(x.is_some(), x.unwrap()); // ok
+    checks_unwrap!(x, x.unwrap()); // ok
+    checks_some!(x.is_some(), x); // ok
     let mut x: Result<(), ()> = Ok(());
     if x.is_ok() {
         x.unwrap(); // unnecessary
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 e40542e2e4f..4013d1ed667 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -1,5 +1,5 @@
 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:15:9
+  --> $DIR/simple_conditionals.rs:39:9
    |
 LL |     if x.is_some() {
    |        ----------- the check is happening here
@@ -13,7 +13,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:17:9
+  --> $DIR/simple_conditionals.rs:41:9
    |
 LL |     if x.is_some() {
    |        ----------- because of this check
@@ -28,7 +28,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:20:9
+  --> $DIR/simple_conditionals.rs:44:9
    |
 LL |     if x.is_none() {
    |        ----------- because of this check
@@ -36,7 +36,7 @@ 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`.
-  --> $DIR/simple_conditionals.rs:22:9
+  --> $DIR/simple_conditionals.rs:46:9
    |
 LL |     if x.is_none() {
    |        ----------- the check is happening here
@@ -58,7 +58,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`.
-  --> $DIR/simple_conditionals.rs:27:9
+  --> $DIR/simple_conditionals.rs:54:9
    |
 LL |     if x.is_ok() {
    |        --------- the check is happening here
@@ -66,7 +66,7 @@ LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
-  --> $DIR/simple_conditionals.rs:28:9
+  --> $DIR/simple_conditionals.rs:55:9
    |
 LL |     if x.is_ok() {
    |        --------- because of this check
@@ -75,7 +75,7 @@ LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:30:9
+  --> $DIR/simple_conditionals.rs:57:9
    |
 LL |     if x.is_ok() {
    |        --------- because of this check
@@ -84,7 +84,7 @@ 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`.
-  --> $DIR/simple_conditionals.rs:31:9
+  --> $DIR/simple_conditionals.rs:58:9
    |
 LL |     if x.is_ok() {
    |        --------- the check is happening here
@@ -93,7 +93,7 @@ LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:34:9
+  --> $DIR/simple_conditionals.rs:61:9
    |
 LL |     if x.is_err() {
    |        ---------- because of this check
@@ -101,7 +101,7 @@ 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`.
-  --> $DIR/simple_conditionals.rs:35:9
+  --> $DIR/simple_conditionals.rs:62:9
    |
 LL |     if x.is_err() {
    |        ---------- the check is happening here
@@ -110,7 +110,7 @@ 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`.
-  --> $DIR/simple_conditionals.rs:37:9
+  --> $DIR/simple_conditionals.rs:64:9
    |
 LL |     if x.is_err() {
    |        ---------- the check is happening here
@@ -119,7 +119,7 @@ LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
-  --> $DIR/simple_conditionals.rs:38:9
+  --> $DIR/simple_conditionals.rs:65:9
    |
 LL |     if x.is_err() {
    |        ---------- because of this check
diff --git a/src/tools/clippy/tests/ui/future_not_send.rs b/src/tools/clippy/tests/ui/future_not_send.rs
index 6d09d71a630..d3a920de4b6 100644
--- a/src/tools/clippy/tests/ui/future_not_send.rs
+++ b/src/tools/clippy/tests/ui/future_not_send.rs
@@ -41,6 +41,7 @@ impl Dummy {
         self.private_future().await;
     }
 
+    #[allow(clippy::manual_async_fn)]
     pub fn public_send(&self) -> impl std::future::Future<Output = bool> {
         async { false }
     }
diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr
index 3b4968ef0a6..d1863701bfe 100644
--- a/src/tools/clippy/tests/ui/future_not_send.stderr
+++ b/src/tools/clippy/tests/ui/future_not_send.stderr
@@ -96,13 +96,13 @@ LL |     }
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:49:37
+  --> $DIR/future_not_send.rs:50:37
    |
 LL | async fn generic_future<T>(t: T) -> T
    |                                     ^ future returned by `generic_future` is not `Send`
    |
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:54:5
+  --> $DIR/future_not_send.rs:55:5
    |
 LL |     let rt = &t;
    |         -- has type `&T` which is not `Send`
@@ -114,7 +114,7 @@ LL | }
    = note: `T` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:65:34
+  --> $DIR/future_not_send.rs:66:34
    |
 LL | async fn unclear_future<T>(t: T) {}
    |                                  ^
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed
new file mode 100644
index 00000000000..6bb1032a172
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed
@@ -0,0 +1,67 @@
+// run-rustfix
+// edition:2018
+#![warn(clippy::manual_async_fn)]
+#![allow(unused)]
+
+use std::future::Future;
+
+async fn fut() -> i32 { 42 }
+
+async fn empty_fut()  {}
+
+async fn core_fut() -> i32 { 42 }
+
+// should be ignored
+fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+    let _ = 42;
+    async move { 42 }
+}
+
+// should be ignored
+fn not_fut() -> i32 {
+    42
+}
+
+// should be ignored
+async fn already_async() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+struct S {}
+impl S {
+    async fn inh_fut() -> i32 {
+        // NOTE: this code is here just to check that the identation is correct in the suggested fix
+        let a = 42;
+        let b = 21;
+        if a < b {
+            let c = 21;
+            let d = 42;
+            if c < d {
+                let _ = 42;
+            }
+        }
+        42
+    }
+
+    async fn meth_fut(&self) -> i32 { 42 }
+
+    async fn empty_fut(&self)  {}
+
+    // should be ignored
+    fn not_fut(&self) -> i32 {
+        42
+    }
+
+    // should be ignored
+    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+        let _ = 42;
+        async move { 42 }
+    }
+
+    // should be ignored
+    async fn already_async(&self) -> impl Future<Output = i32> {
+        async { 42 }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs
new file mode 100644
index 00000000000..d50c919188b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_async_fn.rs
@@ -0,0 +1,79 @@
+// run-rustfix
+// edition:2018
+#![warn(clippy::manual_async_fn)]
+#![allow(unused)]
+
+use std::future::Future;
+
+fn fut() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+fn empty_fut() -> impl Future<Output = ()> {
+    async {}
+}
+
+fn core_fut() -> impl core::future::Future<Output = i32> {
+    async move { 42 }
+}
+
+// should be ignored
+fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+    let _ = 42;
+    async move { 42 }
+}
+
+// should be ignored
+fn not_fut() -> i32 {
+    42
+}
+
+// should be ignored
+async fn already_async() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+struct S {}
+impl S {
+    fn inh_fut() -> impl Future<Output = i32> {
+        async {
+            // NOTE: this code is here just to check that the identation is correct in the suggested fix
+            let a = 42;
+            let b = 21;
+            if a < b {
+                let c = 21;
+                let d = 42;
+                if c < d {
+                    let _ = 42;
+                }
+            }
+            42
+        }
+    }
+
+    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
+    }
+
+    // should be ignored
+    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+        let _ = 42;
+        async move { 42 }
+    }
+
+    // should be ignored
+    async fn already_async(&self) -> impl Future<Output = i32> {
+        async { 42 }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr
new file mode 100644
index 00000000000..f278ee41aa3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr
@@ -0,0 +1,98 @@
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:8:1
+   |
+LL | fn fut() -> impl Future<Output = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::manual-async-fn` implied by `-D warnings`
+help: make the function `async` and return the output of the future directly
+   |
+LL | async fn fut() -> i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL | fn fut() -> impl Future<Output = i32> { 42 }
+   |                                       ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:12:1
+   |
+LL | fn empty_fut() -> impl Future<Output = ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and remove the return type
+   |
+LL | async fn empty_fut()  {
+   | ^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL | fn empty_fut() -> impl Future<Output = ()> {}
+   |                                            ^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:16:1
+   |
+LL | fn core_fut() -> impl core::future::Future<Output = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL | async fn core_fut() -> i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL | fn core_fut() -> impl core::future::Future<Output = i32> { 42 }
+   |                                                          ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:38:5
+   |
+LL |     fn inh_fut() -> impl Future<Output = i32> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL |     async fn inh_fut() -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL |     fn inh_fut() -> impl Future<Output = i32> {
+LL |         // NOTE: this code is here just to check that the identation is correct in the suggested fix
+LL |         let a = 42;
+LL |         let b = 21;
+LL |         if a < b {
+LL |             let c = 21;
+ ...
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:54:5
+   |
+LL |     fn meth_fut(&self) -> impl Future<Output = i32> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL |     async fn meth_fut(&self) -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL |     fn meth_fut(&self) -> impl Future<Output = i32> { 42 }
+   |                                                     ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:58:5
+   |
+LL |     fn empty_fut(&self) -> impl Future<Output = ()> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and remove the return type
+   |
+LL |     async fn empty_fut(&self)  {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL |     fn empty_fut(&self) -> impl Future<Output = ()> {}
+   |                                                     ^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_memcpy.rs b/src/tools/clippy/tests/ui/manual_memcpy.rs
index aa347288875..9c24d6d4db1 100644
--- a/src/tools/clippy/tests/ui/manual_memcpy.rs
+++ b/src/tools/clippy/tests/ui/manual_memcpy.rs
@@ -98,6 +98,21 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
     for i in from..from + 3 {
         dst[i] = src[i - from];
     }
+
+    #[allow(clippy::identity_op)]
+    for i in 0..5 {
+        dst[i - 0] = src[i];
+    }
+
+    #[allow(clippy::reverse_range_loop)]
+    for i in 0..0 {
+        dst[i] = src[i];
+    }
+
+    // `RangeTo` `for` loop - don't trigger lint
+    for i in 0.. {
+        dst[i] = src[i];
+    }
 }
 
 #[warn(clippy::needless_range_loop, clippy::manual_memcpy)]
diff --git a/src/tools/clippy/tests/ui/manual_memcpy.stderr b/src/tools/clippy/tests/ui/manual_memcpy.stderr
index 3dbb2155d4d..bad84a58900 100644
--- a/src/tools/clippy/tests/ui/manual_memcpy.stderr
+++ b/src/tools/clippy/tests/ui/manual_memcpy.stderr
@@ -58,19 +58,31 @@ error: it looks like you're manually copying between slices
   --> $DIR/manual_memcpy.rs:94:14
    |
 LL |     for i in from..from + src.len() {
-   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[0..(from + src.len() - from)])`
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[..(from + src.len() - from)])`
 
 error: it looks like you're manually copying between slices
   --> $DIR/manual_memcpy.rs:98:14
    |
 LL |     for i in from..from + 3 {
-   |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[0..(from + 3 - from)])`
+   |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[..(from + 3 - from)])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/manual_memcpy.rs:105:14
+  --> $DIR/manual_memcpy.rs:103:14
+   |
+LL |     for i in 0..5 {
+   |              ^^^^ help: try replacing the loop by: `dst[..5].clone_from_slice(&src[..5])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:108:14
+   |
+LL |     for i in 0..0 {
+   |              ^^^^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:120:14
    |
 LL |     for i in 0..src.len() {
    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
 
-error: aborting due to 11 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive.rs
new file mode 100644
index 00000000000..7a788f48520
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive.rs
@@ -0,0 +1,137 @@
+#![warn(clippy::manual_non_exhaustive)]
+#![allow(unused)]
+
+mod enums {
+    enum E {
+        A,
+        B,
+        #[doc(hidden)]
+        _C,
+    }
+
+    // user forgot to remove the marker
+    #[non_exhaustive]
+    enum Ep {
+        A,
+        B,
+        #[doc(hidden)]
+        _C,
+    }
+
+    // marker variant does not have doc hidden attribute, should be ignored
+    enum NoDocHidden {
+        A,
+        B,
+        _C,
+    }
+
+    // name of variant with doc hidden does not start with underscore, should be ignored
+    enum NoUnderscore {
+        A,
+        B,
+        #[doc(hidden)]
+        C,
+    }
+
+    // variant with doc hidden is not unit, should be ignored
+    enum NotUnit {
+        A,
+        B,
+        #[doc(hidden)]
+        _C(bool),
+    }
+
+    // variant with doc hidden is the only one, should be ignored
+    enum OnlyMarker {
+        #[doc(hidden)]
+        _A,
+    }
+
+    // variant with multiple markers, should be ignored
+    enum MultipleMarkers {
+        A,
+        #[doc(hidden)]
+        _B,
+        #[doc(hidden)]
+        _C,
+    }
+
+    // already non_exhaustive and no markers, should be ignored
+    #[non_exhaustive]
+    enum NonExhaustive {
+        A,
+        B,
+    }
+}
+
+mod structs {
+    struct S {
+        pub a: i32,
+        pub b: i32,
+        _c: (),
+    }
+
+    // user forgot to remove the private field
+    #[non_exhaustive]
+    struct Sp {
+        pub a: i32,
+        pub b: i32,
+        _c: (),
+    }
+
+    // some other fields are private, should be ignored
+    struct PrivateFields {
+        a: i32,
+        pub b: i32,
+        _c: (),
+    }
+
+    // private field name does not start with underscore, should be ignored
+    struct NoUnderscore {
+        pub a: i32,
+        pub b: i32,
+        c: (),
+    }
+
+    // private field is not unit type, should be ignored
+    struct NotUnit {
+        pub a: i32,
+        pub b: i32,
+        _c: i32,
+    }
+
+    // private field is the only field, should be ignored
+    struct OnlyMarker {
+        _a: (),
+    }
+
+    // already non exhaustive and no private fields, should be ignored
+    #[non_exhaustive]
+    struct NonExhaustive {
+        pub a: i32,
+        pub b: i32,
+    }
+}
+
+mod tuple_structs {
+    struct T(pub i32, pub i32, ());
+
+    // user forgot to remove the private field
+    #[non_exhaustive]
+    struct Tp(pub i32, pub i32, ());
+
+    // some other fields are private, should be ignored
+    struct PrivateFields(pub i32, i32, ());
+
+    // private field is not unit type, should be ignored
+    struct NotUnit(pub i32, pub i32, i32);
+
+    // private field is the only field, should be ignored
+    struct OnlyMarker(());
+
+    // already non exhaustive and no private fields, should be ignored
+    #[non_exhaustive]
+    struct NonExhaustive(pub i32, pub i32);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive.stderr
new file mode 100644
index 00000000000..613c5e8ca1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive.stderr
@@ -0,0 +1,103 @@
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:5:5
+   |
+LL |       enum E {
+   |       ^-----
+   |       |
+   |  _____help: add the attribute: `#[non_exhaustive] enum E`
+   | |
+LL | |         A,
+LL | |         B,
+LL | |         #[doc(hidden)]
+LL | |         _C,
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
+help: remove this variant
+  --> $DIR/manual_non_exhaustive.rs:9:9
+   |
+LL |         _C,
+   |         ^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:14:5
+   |
+LL | /     enum Ep {
+LL | |         A,
+LL | |         B,
+LL | |         #[doc(hidden)]
+LL | |         _C,
+LL | |     }
+   | |_____^
+   |
+help: remove this variant
+  --> $DIR/manual_non_exhaustive.rs:18:9
+   |
+LL |         _C,
+   |         ^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:68:5
+   |
+LL |       struct S {
+   |       ^-------
+   |       |
+   |  _____help: add the attribute: `#[non_exhaustive] struct S`
+   | |
+LL | |         pub a: i32,
+LL | |         pub b: i32,
+LL | |         _c: (),
+LL | |     }
+   | |_____^
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:71:9
+   |
+LL |         _c: (),
+   |         ^^^^^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:76:5
+   |
+LL | /     struct Sp {
+LL | |         pub a: i32,
+LL | |         pub b: i32,
+LL | |         _c: (),
+LL | |     }
+   | |_____^
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:79:9
+   |
+LL |         _c: (),
+   |         ^^^^^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:117:5
+   |
+LL |     struct T(pub i32, pub i32, ());
+   |     --------^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: add the attribute: `#[non_exhaustive] struct T`
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:117:32
+   |
+LL |     struct T(pub i32, pub i32, ());
+   |                                ^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:121:5
+   |
+LL |     struct Tp(pub i32, pub i32, ());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:121:33
+   |
+LL |     struct Tp(pub i32, pub i32, ());
+   |                                 ^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.rs b/src/tools/clippy/tests/ui/match_on_vec_items.rs
index 0bb39d77e46..30415e3b94d 100644
--- a/src/tools/clippy/tests/ui/match_on_vec_items.rs
+++ b/src/tools/clippy/tests/ui/match_on_vec_items.rs
@@ -120,6 +120,27 @@ fn match_with_array() {
     }
 }
 
+fn match_with_endless_range() {
+    let arr = vec![0, 1, 2, 3];
+    let range = ..;
+
+    // Ok
+    match arr[range] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        [0, 1, 2, 3] => println!("0, 1, 2, 3"),
+        _ => {},
+    }
+
+    // Ok
+    match arr[..] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        [0, 1, 2, 3] => println!("0, 1, 2, 3"),
+        _ => {},
+    }
+}
+
 fn main() {
     match_with_wildcard();
     match_without_wildcard();
@@ -127,4 +148,5 @@ fn main() {
     match_vec_ref();
     match_with_get();
     match_with_array();
+    match_with_endless_range();
 }
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
index f5fcabf63fd..e99c98ac79f 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -2,6 +2,7 @@
 
 #![warn(clippy::while_let_on_iterator)]
 #![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![feature(or_patterns)]
 
 fn base() {
     let mut iter = 1..20;
@@ -77,6 +78,62 @@ fn refutable() {
     // */
 }
 
+fn refutable2() {
+    // Issue 3780
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.windows(2);
+        while let Some([x, y]) = it.next() {
+            println!("x: {}", x);
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([x, ..]) = it.next() {
+            println!("x: {}", x);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([.., y]) = it.next() {
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        for [..] in it {}
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        while let Some([1]) = it.next() {}
+
+        let mut it = v.iter();
+        for [_x] in it {}
+    }
+
+    // binding
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter();
+        while let Some(x @ 1) = it.next() {
+            println!("{}", x);
+        }
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        for x @ [_] in it {
+            println!("{:?}", x);
+        }
+    }
+
+    // false negative
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter().map(Some);
+        while let Some(Some(_) | None) = it.next() {
+            println!("1");
+        }
+    }
+}
+
 fn nested_loops() {
     let a = [42, 1337];
     let mut y = a.iter();
@@ -152,6 +209,7 @@ fn issue1654() {
 fn main() {
     base();
     refutable();
+    refutable2();
     nested_loops();
     issue1121();
     issue2965();
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
index 04dce8a0289..ba13172428e 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -2,6 +2,7 @@
 
 #![warn(clippy::while_let_on_iterator)]
 #![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![feature(or_patterns)]
 
 fn base() {
     let mut iter = 1..20;
@@ -77,6 +78,62 @@ fn refutable() {
     // */
 }
 
+fn refutable2() {
+    // Issue 3780
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.windows(2);
+        while let Some([x, y]) = it.next() {
+            println!("x: {}", x);
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([x, ..]) = it.next() {
+            println!("x: {}", x);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([.., y]) = it.next() {
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([..]) = it.next() {}
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        while let Some([1]) = it.next() {}
+
+        let mut it = v.iter();
+        while let Some([_x]) = it.next() {}
+    }
+
+    // binding
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter();
+        while let Some(x @ 1) = it.next() {
+            println!("{}", x);
+        }
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        while let Some(x @ [_]) = it.next() {
+            println!("{:?}", x);
+        }
+    }
+
+    // false negative
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter().map(Some);
+        while let Some(Some(_) | None) = it.next() {
+            println!("1");
+        }
+    }
+}
+
 fn nested_loops() {
     let a = [42, 1337];
     let mut y = a.iter();
@@ -152,6 +209,7 @@ fn issue1654() {
 fn main() {
     base();
     refutable();
+    refutable2();
     nested_loops();
     issue1121();
     issue2965();
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
index 6de138d7227..aa980d9965c 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -1,5 +1,5 @@
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:8:5
+  --> $DIR/while_let_on_iterator.rs:9:5
    |
 LL |     while let Option::Some(x) = iter.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
@@ -7,22 +7,40 @@ LL |     while let Option::Some(x) = iter.next() {
    = note: `-D clippy::while-let-on-iterator` implied by `-D warnings`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:13:5
+  --> $DIR/while_let_on_iterator.rs:14:5
    |
 LL |     while let Some(x) = iter.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:18:5
+  --> $DIR/while_let_on_iterator.rs:19:5
    |
 LL |     while let Some(_) = iter.next() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:97:9
+  --> $DIR/while_let_on_iterator.rs:102:9
+   |
+LL |         while let Some([..]) = it.next() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:109:9
+   |
+LL |         while let Some([_x]) = it.next() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:122:9
+   |
+LL |         while let Some(x @ [_]) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:154:9
    |
 LL |         while let Some(_) = y.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
 
-error: aborting due to 4 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index ed6cc00ef04..67423e6ec1d 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -155,3 +155,76 @@ fn test_weird_formatting() {
     exported();
     foo();
 }
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_futher_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
index c6d6efaece8..3ad1a29aeba 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -156,3 +156,76 @@ fn test_weird_formatting() {
     exported();
     foo();
 }
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_futher_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use super_imports::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::*;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::*;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index 050e4c6304f..fab43b738eb 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -92,5 +92,35 @@ LL |       use crate:: fn_mod::
 LL | |         *;
    | |_________^ help: try: `crate:: fn_mod::foo`
 
-error: aborting due to 15 previous errors
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:164:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:199:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:207:13
+   |
+LL |         use super_imports::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:216:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:225:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 3a8a5491255..93a414ff6b9 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -347,7 +347,10 @@ pub fn run_tests(config: Config) {
         Ok(true) => {}
         Ok(false) => panic!("Some tests failed"),
         Err(e) => {
-            println!("I/O failure during tests: {:?}", e);
+            // We don't know if tests passed or not, but if there was an error
+            // during testing we don't want to just suceeed (we may not have
+            // tested something), so fail.
+            panic!("I/O failure during tests: {:?}", e);
         }
     }
 }
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 7f3366288d126408815eeafa8d7cd6e9f3ea56b
+Subproject 10419b3f2fc625bb9d746c16d768e433a894484
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index e6e758dccdf..ff41197faa1 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -23,6 +23,6 @@ codespan-reporting = { version = "0.5", optional = true }
 rustc-workspace-hack = "1.0.0"
 
 [dependencies.mdbook]
-version = "0.3.0"
+version = "0.3.7"
 default-features = false
 features = ["search"]
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 03f06fc1c6c..1fa46ce99f5 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -181,7 +181,7 @@ function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
     for (var i = 0; i < thingsToLoad.length; ++i) {
         var tmp = funcToCall(fileContent, thingsToLoad[i]);
         if (tmp === null) {
-            console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
+            console.log('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
             process.exit(1);
         }
         content += tmp;
@@ -218,12 +218,13 @@ function lookForEntry(entry, data) {
     return null;
 }
 
-function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) {
+function loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate) {
     if (searchIndex[searchIndex.length - 1].length === 0) {
         searchIndex.pop();
     }
     searchIndex.pop();
-    searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
+    var fullSearchIndex = searchIndex.join("\n") + '\nexports.rawSearchIndex = searchIndex;';
+    searchIndex = loadContent(fullSearchIndex);
     var finalJS = "";
 
     var arraysToLoad = ["itemTypes"];
@@ -235,34 +236,28 @@ function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) {
     // execQuery last parameter is built in buildIndex.
     // buildIndex requires the hashmap from search-index.
     var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
-                           "getQuery", "buildIndex", "execQuery", "execSearch"];
+                           "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch"];
 
+    ALIASES = {};
     finalJS += 'window = { "currentCrate": "' + crate + '" };\n';
     finalJS += 'var rootPath = "../";\n';
-    finalJS += aliases;
+    finalJS += loadThings(["onEach"], 'function', extractFunction, storageJs);
     finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
     finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
     finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
 
     var loaded = loadContent(finalJS);
-    var index = loaded.buildIndex(searchIndex.searchIndex);
+    var index = loaded.buildIndex(searchIndex.rawSearchIndex);
 
     return [loaded, index];
 }
 
-function runChecks(testFile, loaded, index) {
-    var errors = 0;
-    var loadedFile = loadContent(
-        readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
-
-    const expected = loadedFile.EXPECTED;
-    const query = loadedFile.QUERY;
+function runSearch(query, expected, index, loaded, loadedFile, queryName) {
     const filter_crate = loadedFile.FILTER_CRATE;
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
-    const should_fail = loadedFile.should_fail;
 
-    var results = loaded.execSearch(loaded.getQuery(query), index);
+    var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
     var error_text = [];
 
     for (var key in expected) {
@@ -278,41 +273,77 @@ function runChecks(testFile, loaded, index) {
         for (var i = 0; i < entry.length; ++i) {
             var entry_pos = lookForEntry(entry[i], results[key]);
             if (entry_pos === null) {
-                error_text.push("==> Result not found in '" + key + "': '" +
+                error_text.push(queryName + "==> Result not found in '" + key + "': '" +
                                 JSON.stringify(entry[i]) + "'");
             } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
-                error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
-                                "expected '" + JSON.stringify(entry[i]) + "' but found '" +
+                error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) +
+                                ": expected '" + JSON.stringify(entry[i]) + "' but found '" +
                                 JSON.stringify(results[key][i]) + "'");
             } else if (ignore_order === false && entry_pos < prev_pos) {
-                error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
-                                " before '" + JSON.stringify(results[key][entry_pos]) + "'");
+                error_text.push(queryName + "==> '" + JSON.stringify(entry[i]) + "' was supposed " +
+                                "to be before '" + JSON.stringify(results[key][entry_pos]) + "'");
             } else {
                 prev_pos = entry_pos;
             }
         }
     }
-    if (error_text.length === 0 && should_fail === true) {
-        errors += 1;
-        console.error("FAILED");
-        console.error("==> Test was supposed to fail but all items were found...");
-    } else if (error_text.length !== 0 && should_fail === false) {
-        errors += 1;
-        console.error("FAILED");
-        console.error(error_text.join("\n"));
+    return error_text;
+}
+
+function checkResult(error_text, loadedFile, displaySuccess) {
+    if (error_text.length === 0 && loadedFile.should_fail === true) {
+        console.log("FAILED");
+        console.log("==> Test was supposed to fail but all items were found...");
+    } else if (error_text.length !== 0 && loadedFile.should_fail === false) {
+        console.log("FAILED");
+        console.log(error_text.join("\n"));
     } else {
+        if (displaySuccess) {
+            console.log("OK");
+        }
+        return 0;
+    }
+    return 1;
+}
+
+function runChecks(testFile, loaded, index) {
+    var loadedFile = loadContent(
+        readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
+
+    const expected = loadedFile.EXPECTED;
+    const query = loadedFile.QUERY;
+
+    if (Array.isArray(query)) {
+        if (!Array.isArray(expected)) {
+            console.log("FAILED");
+            console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
+            return 1;
+        } else if (query.length !== expected.length) {
+            console.log("FAILED");
+            console.log("==> QUERY variable should have the same length as EXPECTED");
+            return 1;
+        }
+        for (var i = 0; i < query.length; ++i) {
+            var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
+                "[ query `" + query[i] + "`]");
+            if (checkResult(error_text, loadedFile, false) !== 0) {
+                return 1;
+            }
+        }
         console.log("OK");
+        return 0;
     }
-    return errors;
+    var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
+    return checkResult(error_text, loadedFile, true);
 }
 
 function load_files(doc_folder, resource_suffix, crate) {
     var mainJs = readFile(path.join(doc_folder, "main" + resource_suffix + ".js"));
-    var aliases = readFile(path.join(doc_folder, "aliases" + resource_suffix + ".js"));
+    var storageJs = readFile(path.join(doc_folder, "storage" + resource_suffix + ".js"));
     var searchIndex = readFile(
         path.join(doc_folder, "search-index" + resource_suffix + ".js")).split("\n");
 
-    return loadMainJsAndIndex(mainJs, aliases, searchIndex, crate);
+    return loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate);
 }
 
 function showHelp() {
@@ -349,7 +380,7 @@ function parseOptions(args) {
             || args[i] === "--crate-name") {
             i += 1;
             if (i >= args.length) {
-                console.error("Missing argument after `" + args[i - 1] + "` option.");
+                console.log("Missing argument after `" + args[i - 1] + "` option.");
                 return null;
             }
             opts[correspondances[args[i - 1]]] = args[i];
@@ -357,17 +388,17 @@ function parseOptions(args) {
             showHelp();
             process.exit(0);
         } else {
-            console.error("Unknown option `" + args[i] + "`.");
-            console.error("Use `--help` to see the list of options");
+            console.log("Unknown option `" + args[i] + "`.");
+            console.log("Use `--help` to see the list of options");
             return null;
         }
     }
     if (opts["doc_folder"].length < 1) {
-        console.error("Missing `--doc-folder` option.");
+        console.log("Missing `--doc-folder` option.");
     } else if (opts["crate_name"].length < 1) {
-        console.error("Missing `--crate-name` option.");
+        console.log("Missing `--crate-name` option.");
     } else if (opts["test_folder"].length < 1 && opts["test_file"].length < 1) {
-        console.error("At least one of `--test-folder` or `--test-file` option is required.");
+        console.log("At least one of `--test-folder` or `--test-file` option is required.");
     } else {
         return opts;
     }