about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/regression.md2
-rw-r--r--Cargo.lock13
-rw-r--r--Cargo.toml1
-rw-r--r--compiler/rustc_ast/src/token.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs26
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml7
-rw-r--r--compiler/rustc_codegen_cranelift/.vscode/settings.json2
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock45
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml6
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md5
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock19
-rwxr-xr-xcompiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh2
-rw-r--r--compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch4
-rw-r--r--compiler/rustc_codegen_cranelift/docs/env_vars.md15
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs43
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/ext_config.sh2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh7
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs15
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/backend.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs146
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/src/config.rs107
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs67
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs71
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs69
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs207
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/mod.rs58
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs64
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs144
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs136
-rw-r--r--compiler/rustc_codegen_cranelift/src/linkage.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs72
-rw-r--r--compiler/rustc_codegen_cranelift/src/metadata.rs57
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs17
-rw-r--r--compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs34
-rw-r--r--compiler/rustc_codegen_cranelift/src/optimize/mod.rs17
-rw-r--r--compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs486
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs49
-rw-r--r--compiler/rustc_codegen_cranelift/src/trap.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs36
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs64
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs27
-rw-r--r--compiler/rustc_data_structures/Cargo.toml1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0136.md4
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs10
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs19
-rw-r--r--compiler/rustc_feature/src/active.rs10
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs7
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs2
-rw-r--r--compiler/rustc_infer/src/traits/util.rs4
-rw-r--r--compiler/rustc_interface/src/queries.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs143
-rw-r--r--compiler/rustc_lint/src/context.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp6
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs6
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/hir/map/collector.rs139
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs321
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs25
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs13
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs13
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs20
-rw-r--r--compiler/rustc_middle/src/ty/context.rs7
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs14
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs35
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs48
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs71
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs115
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs11
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs20
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs1
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs6
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs2
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs4
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs13
-rw-r--r--compiler/rustc_mir/src/transform/coverage/mod.rs6
-rw-r--r--compiler/rustc_mir/src/transform/coverage/spans.rs254
-rw-r--r--compiler/rustc_mir/src/transform/coverage/tests.rs13
-rw-r--r--compiler/rustc_mir/src/util/spanview.rs19
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs14
-rw-r--r--compiler/rustc_passes/src/dead.rs4
-rw-r--r--compiler/rustc_passes/src/entry.rs51
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs19
-rw-r--r--compiler/rustc_query_impl/src/stats.rs9
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs34
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs20
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs8
-rw-r--r--compiler/rustc_resolve/src/lib.rs35
-rw-r--r--compiler/rustc_session/src/config.rs37
-rw-r--r--compiler/rustc_session/src/options.rs1086
-rw-r--r--compiler/rustc_session/src/session.rs30
-rw-r--r--compiler/rustc_span/src/symbol.rs5
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs10
-rw-r--r--compiler/rustc_target/src/asm/arm.rs3
-rw-r--r--compiler/rustc_target/src/asm/hexagon.rs3
-rw-r--r--compiler/rustc_target/src/asm/riscv.rs3
-rw-r--r--compiler/rustc_target/src/asm/x86.rs32
-rw-r--r--compiler/rustc_target/src/spec/i386_apple_ios.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_linux_android.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_freebsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_haiku.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_netbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_openbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_wrs_vxworks.rs3
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_tvos.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fuchsia.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_linux_android.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_solaris.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_sun_solaris.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_redox.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs7
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs6
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs6
-rw-r--r--compiler/rustc_typeck/src/check/check.rs30
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs16
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs1
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs25
-rw-r--r--compiler/rustc_typeck/src/collect.rs28
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs4
-rw-r--r--compiler/rustc_typeck/src/lib.rs283
-rw-r--r--library/alloc/src/collections/btree/node.rs8
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/vec/mod.rs4
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/core/src/cmp.rs2
-rw-r--r--library/core/src/hint.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs1
-rw-r--r--library/proc_macro/src/lib.rs3
-rw-r--r--library/std/src/env.rs15
-rw-r--r--library/std/src/ffi/os_str.rs14
-rw-r--r--library/std/src/path.rs14
-rw-r--r--library/std/src/primitive_docs.rs49
-rw-r--r--library/std/src/sync/mutex.rs21
-rw-r--r--library/std/src/sys/hermit/cmath.rs29
-rw-r--r--library/std/src/sys/hermit/mod.rs1
-rw-r--r--library/std/src/sys/sgx/cmath.rs31
-rw-r--r--library/std/src/sys/sgx/ext/arch.rs10
-rw-r--r--library/std/src/sys/sgx/mod.rs1
-rw-r--r--library/std/src/sys/unix/cmath.rs55
-rw-r--r--library/std/src/sys/unix/ext/fs.rs26
-rw-r--r--library/std/src/sys/unix/fs.rs7
-rw-r--r--library/std/src/sys/unix/mod.rs1
-rw-r--r--library/std/src/sys/unsupported/cmath.rs29
-rw-r--r--library/std/src/sys/unsupported/mod.rs1
-rw-r--r--library/std/src/sys/wasi/mod.rs2
-rw-r--r--library/std/src/sys/wasm/mod.rs2
-rw-r--r--library/std/src/sys/windows/process.rs28
-rw-r--r--library/std/src/sys_common/os_str_bytes.rs14
-rw-r--r--rustfmt.toml2
-rw-r--r--src/bootstrap/bootstrap.py12
-rw-r--r--src/bootstrap/builder.rs5
-rw-r--r--src/bootstrap/check.rs14
-rw-r--r--src/bootstrap/defaults/config.codegen.toml2
-rw-r--r--src/bootstrap/defaults/config.compiler.toml2
-rw-r--r--src/bootstrap/test.rs20
-rw-r--r--src/bootstrap/tool.rs5
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile1
m---------src/doc/book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support.md305
-rw-r--r--src/doc/rustc/src/target-tier-policy.md11
-rw-r--r--src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md2
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md24
-rw-r--r--src/librustdoc/clean/auto_trait.rs1
-rw-r--r--src/librustdoc/clean/blanket_impl.rs7
-rw-r--r--src/librustdoc/clean/inline.rs9
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/librustdoc/clean/types.rs69
-rw-r--r--src/librustdoc/config.rs10
-rw-r--r--src/librustdoc/doctest.rs3
-rw-r--r--src/librustdoc/formats/cache.rs21
-rw-r--r--src/librustdoc/html/format.rs24
-rw-r--r--src/librustdoc/html/render/cache.rs47
-rw-r--r--src/librustdoc/html/render/context.rs14
-rw-r--r--src/librustdoc/html/render/mod.rs211
-rw-r--r--src/librustdoc/html/render/print_item.rs7
-rw-r--r--src/librustdoc/html/static/main.js57
-rw-r--r--src/librustdoc/html/static/rustdoc.css30
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/librustdoc/json/mod.rs11
-rw-r--r--src/librustdoc/lib.rs3
m---------src/llvm-project0
-rw-r--r--src/test/assembly/stack-probes.rs42
-rw-r--r--src/test/codegen/asm-multiple-options.rs2
-rw-r--r--src/test/codegen/asm-options.rs2
-rw-r--r--src/test/codegen/async-fn-debug-msvc.rs24
-rw-r--r--src/test/codegen/async-fn-debug.rs29
-rw-r--r--src/test/codegen/generator-debug-msvc.rs24
-rw-r--r--src/test/codegen/generator-debug.rs29
-rw-r--r--src/test/codegen/stack-probes.rs2
-rw-r--r--src/test/debuginfo/extern-c-fn.rs13
-rw-r--r--src/test/debuginfo/generator-objects.rs20
-rw-r--r--src/test/debuginfo/issue-57822.rs4
-rw-r--r--src/test/debuginfo/pretty-huge-vec.rs2
-rw-r--r--src/test/incremental/commandline-args.rs7
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs10
-rw-r--r--src/test/incremental/hashes/type_defs.rs14
-rw-r--r--src/test/incremental/ich_nested_items.rs5
-rw-r--r--src/test/pretty/asm.pp2
-rw-r--r--src/test/pretty/asm.rs2
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt42
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt83
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt6
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt22
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt195
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt18
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt19
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt2
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt89
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt10
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt12
-rw-r--r--src/test/run-make-fulldeps/coverage/closure_macro.rs40
-rw-r--r--src/test/run-make-fulldeps/coverage/closure_macro_async.rs81
-rw-r--r--src/test/run-make-fulldeps/coverage/issue-83601.rs14
-rw-r--r--src/test/run-make-fulldeps/coverage/issue-84561.rs182
-rw-r--r--src/test/run-make-fulldeps/coverage/no_cov_crate.rs17
-rw-r--r--src/test/run-make-fulldeps/coverage/no_cov_func.rs18
-rw-r--r--src/test/run-make-fulldeps/coverage/try_error_result.rs84
-rw-r--r--src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile2
-rw-r--r--src/test/rustdoc-ui/no-run-flag-error.rs6
-rw-r--r--src/test/rustdoc-ui/no-run-flag-error.stderr2
-rw-r--r--src/test/rustdoc-ui/no-run-flag.rs38
-rw-r--r--src/test/rustdoc-ui/no-run-flag.stdout12
-rw-r--r--src/test/rustdoc/auto_aliases.rs2
-rw-r--r--src/test/rustdoc/empty-impls.rs19
-rw-r--r--src/test/rustdoc/issue-53812.rs10
-rw-r--r--src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs2
-rw-r--r--src/test/ui/asm/sym.rs2
-rw-r--r--src/test/ui/associated-consts/associated-const-in-trait.rs2
-rw-r--r--src/test/ui/async-await/async-borrowck-escaping-block-error.stderr6
-rw-r--r--src/test/ui/async-await/issue-68523.rs1
-rw-r--r--src/test/ui/async-await/issue-68523.stderr13
-rw-r--r--src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-closures-two-mut.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-closures-unique.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-closures-use-after-free.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-insert-during-each.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-loan-rcvr.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-move-by-capture.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr4
-rw-r--r--src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr2
-rw-r--r--src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr2
-rw-r--r--src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs32
-rw-r--r--src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs20
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr28
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs20
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr28
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr27
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr31
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs26
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr30
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr6
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr4
-rw-r--r--src/test/ui/const-generics/issues/issue-83466.rs17
-rw-r--r--src/test/ui/const-generics/issues/issue-83466.stderr22
-rw-r--r--src/test/ui/consts/const-eval/auxiliary/stability.rs1
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr.rs1
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr.stderr10
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail.rs1
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr2
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs1
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr10
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs1
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr8
-rw-r--r--src/test/ui/consts/const-eval/double_promotion.rs2
-rw-r--r--src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs2
-rw-r--r--src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr2
-rw-r--r--src/test/ui/consts/const-eval/promoted_const_fn_fail.rs2
-rw-r--r--src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs2
-rw-r--r--src/test/ui/consts/const-eval/simd/insert_extract.rs1
-rw-r--r--src/test/ui/consts/const-eval/union-const-eval-field.rs1
-rw-r--r--src/test/ui/consts/const-eval/union-const-eval-field.stderr2
-rw-r--r--src/test/ui/consts/const-eval/union-ice.rs1
-rw-r--r--src/test/ui/consts/const-eval/union-ice.stderr6
-rw-r--r--src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr14
-rw-r--r--src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr14
-rw-r--r--src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs1
-rw-r--r--src/test/ui/consts/const-fn-error.rs2
-rw-r--r--src/test/ui/consts/const-fn-error.stderr14
-rw-r--r--src/test/ui/consts/const-fn-mismatch.rs2
-rw-r--r--src/test/ui/consts/const-fn-mismatch.stderr2
-rw-r--r--src/test/ui/consts/const-fn-not-in-trait.rs2
-rw-r--r--src/test/ui/consts/const-fn-not-in-trait.stderr4
-rw-r--r--src/test/ui/consts/const-fn-not-safe-for-const.rs2
-rw-r--r--src/test/ui/consts/const-fn-type-name-any.rs1
-rw-r--r--src/test/ui/consts/const-fn-type-name.rs1
-rw-r--r--src/test/ui/consts/const-mut-refs/const_mut_address_of.rs1
-rw-r--r--src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs1
-rw-r--r--src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr12
-rw-r--r--src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs1
-rw-r--r--src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr8
-rw-r--r--src/test/ui/consts/const_constructor/const-construct-call.rs6
-rw-r--r--src/test/ui/consts/const_constructor/const_constructor_qpath.rs3
-rw-r--r--src/test/ui/consts/const_let_assign3.rs2
-rw-r--r--src/test/ui/consts/const_let_assign3.stderr6
-rw-r--r--src/test/ui/consts/const_unsafe_unreachable.rs1
-rw-r--r--src/test/ui/consts/const_unsafe_unreachable_ub.rs1
-rw-r--r--src/test/ui/consts/const_unsafe_unreachable_ub.stderr12
-rw-r--r--src/test/ui/consts/control-flow/basics.rs1
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs4
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs2
-rw-r--r--src/test/ui/consts/promote-not.rs2
-rw-r--r--src/test/ui/consts/rustc-args-required-const.rs2
-rw-r--r--src/test/ui/consts/stable-precise-live-drops-in-libcore.rs2
-rw-r--r--src/test/ui/entry-point/auxiliary/main_functions.rs1
-rw-r--r--src/test/ui/entry-point/imported_main_conflict.rs7
-rw-r--r--src/test/ui/entry-point/imported_main_conflict.stderr18
-rw-r--r--src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs12
-rw-r--r--src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr17
-rw-r--r--src/test/ui/entry-point/imported_main_const_forbidden.rs7
-rw-r--r--src/test/ui/entry-point/imported_main_const_forbidden.stderr17
-rw-r--r--src/test/ui/entry-point/imported_main_from_extern_crate.rs9
-rw-r--r--src/test/ui/entry-point/imported_main_from_extern_crate.stderr10
-rw-r--r--src/test/ui/entry-point/imported_main_from_inner_mod.rs9
-rw-r--r--src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs11
-rw-r--r--src/test/ui/error-codes/E0504.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr21
-rw-r--r--src/test/ui/feature-gates/feature-gate-imported_main.rs6
-rw-r--r--src/test/ui/feature-gates/feature-gate-imported_main.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-no_coverage.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-no_coverage.stderr13
-rw-r--r--src/test/ui/generator/yield-while-ref-reborrowed.stderr2
-rw-r--r--src/test/ui/generic-associated-types/gat-in-trait-path.rs3
-rw-r--r--src/test/ui/generic-associated-types/gat-in-trait-path.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-67510-pass.rs3
-rw-r--r--src/test/ui/generic-associated-types/issue-67510-pass.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-76535.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-76535.stderr37
-rw-r--r--src/test/ui/generic-associated-types/issue-78671.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-78671.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-79422.rs3
-rw-r--r--src/test/ui/generic-associated-types/issue-79422.stderr38
-rw-r--r--src/test/ui/generic-associated-types/trait-objects.rs16
-rw-r--r--src/test/ui/generic-associated-types/trait-objects.stderr18
-rw-r--r--src/test/ui/issues/issue-11192.stderr2
-rw-r--r--src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr2
-rw-r--r--src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr2
-rw-r--r--src/test/ui/issues/issue-61623.stderr2
-rw-r--r--src/test/ui/issues/issue-6801.stderr2
-rw-r--r--src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs14
-rw-r--r--src/test/ui/lifetimes/issue-84604.rs9
-rw-r--r--src/test/ui/macros/edition-macro-pats.rs7
-rw-r--r--src/test/ui/macros/macro-or-patterns-back-compat.fixed13
-rw-r--r--src/test/ui/macros/macro-or-patterns-back-compat.rs7
-rw-r--r--src/test/ui/macros/macro-or-patterns-back-compat.stderr20
-rw-r--r--src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs13
-rw-r--r--src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr24
-rw-r--r--src/test/ui/nll/closure-access-spans.stderr4
-rw-r--r--src/test/ui/nll/closure-borrow-spans.stderr12
-rw-r--r--src/test/ui/nll/closure-captures.stderr12
-rw-r--r--src/test/ui/nll/closure-use-spans.stderr4
-rw-r--r--src/test/ui/nll/closures-in-loops.stderr2
-rw-r--r--src/test/ui/nll/issue-51268.stderr2
-rw-r--r--src/test/ui/or-patterns/macro-pat.rs3
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs2
-rw-r--r--src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs1
-rw-r--r--src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr13
-rw-r--r--src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs2
-rw-r--r--src/test/ui/typeck/issue-75883.rs22
-rw-r--r--src/test/ui/typeck/issue-75883.stderr52
-rw-r--r--src/test/ui/typeck/issue-80779.rs13
-rw-r--r--src/test/ui/typeck/issue-80779.stderr21
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/src/driver.rs2
-rw-r--r--src/tools/clippy/tests/compile-test.rs9
m---------src/tools/miri16
m---------src/tools/rust-analyzer40
-rw-r--r--src/tools/tidy/src/features.rs9
-rw-r--r--src/version2
436 files changed, 5754 insertions, 3787 deletions
diff --git a/.github/ISSUE_TEMPLATE/regression.md b/.github/ISSUE_TEMPLATE/regression.md
index ffab883987c..c0e90824a71 100644
--- a/.github/ISSUE_TEMPLATE/regression.md
+++ b/.github/ISSUE_TEMPLATE/regression.md
@@ -1,7 +1,7 @@
 ---
 name: Regression
 about: Report something that unexpectedly changed between Rust versions.
-labels: C-bug regression-untriaged
+labels: C-bug, regression-untriaged
 ---
 <!--
 Thank you for filing a regression report! 🐛 A regression is something that changed between versions of Rust but was not supposed to.
diff --git a/Cargo.lock b/Cargo.lock
index b3fa511839b..a55ef7b6143 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -583,6 +583,19 @@ name = "clippy-mini-macro-test"
 version = "0.2.0"
 
 [[package]]
+name = "clippy_dev"
+version = "0.0.1"
+dependencies = [
+ "bytecount",
+ "clap",
+ "itertools 0.9.0",
+ "opener",
+ "regex",
+ "shell-escape",
+ "walkdir",
+]
+
+[[package]]
 name = "clippy_lints"
 version = "0.1.53"
 dependencies = [
diff --git a/Cargo.toml b/Cargo.toml
index 02011357eac..327afe35c2f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ members = [
   "src/rustdoc-json-types",
   "src/tools/cargotest",
   "src/tools/clippy",
+  "src/tools/clippy/clippy_dev",
   "src/tools/compiletest",
   "src/tools/error_index_generator",
   "src/tools/linkchecker",
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 10d48a55bb5..15f46ef5d7f 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -688,16 +688,12 @@ pub enum NonterminalKind {
     Item,
     Block,
     Stmt,
-    Pat2015 {
-        /// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the
-        /// edition of the span. This is used for diagnostics.
-        inferred: bool,
-    },
-    Pat2021 {
-        /// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the
+    PatParam {
+        /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
         /// edition of the span. This is used for diagnostics.
         inferred: bool,
     },
+    PatWithOr,
     Expr,
     Ty,
     Ident,
@@ -722,12 +718,11 @@ impl NonterminalKind {
             sym::stmt => NonterminalKind::Stmt,
             sym::pat => match edition() {
                 Edition::Edition2015 | Edition::Edition2018 => {
-                    NonterminalKind::Pat2015 { inferred: true }
+                    NonterminalKind::PatParam { inferred: true }
                 }
-                Edition::Edition2021 => NonterminalKind::Pat2021 { inferred: true },
+                Edition::Edition2021 => NonterminalKind::PatWithOr,
             },
-            sym::pat2015 => NonterminalKind::Pat2015 { inferred: false },
-            sym::pat2021 => NonterminalKind::Pat2021 { inferred: false },
+            sym::pat_param => NonterminalKind::PatParam { inferred: false },
             sym::expr => NonterminalKind::Expr,
             sym::ty => NonterminalKind::Ty,
             sym::ident => NonterminalKind::Ident,
@@ -745,10 +740,8 @@ impl NonterminalKind {
             NonterminalKind::Item => sym::item,
             NonterminalKind::Block => sym::block,
             NonterminalKind::Stmt => sym::stmt,
-            NonterminalKind::Pat2015 { inferred: false } => sym::pat2015,
-            NonterminalKind::Pat2021 { inferred: false } => sym::pat2021,
-            NonterminalKind::Pat2015 { inferred: true }
-            | NonterminalKind::Pat2021 { inferred: true } => sym::pat,
+            NonterminalKind::PatParam { inferred: false } => sym::pat_param,
+            NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
             NonterminalKind::Expr => sym::expr,
             NonterminalKind::Ty => sym::ty,
             NonterminalKind::Ident => sym::ident,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 75dfe951c94..bf70a41fd79 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -338,7 +338,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let mut generic_args = vec![];
         for (idx, arg) in args.into_iter().enumerate() {
             if legacy_args_idx.contains(&idx) {
-                let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+                let parent_def_id = self.current_hir_id_owner.0;
                 let node_id = self.resolver.next_node_id();
 
                 // Add a definition for the in-band const def.
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 44056df4ab9..e7c566e586c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -165,7 +165,7 @@ struct LoweringContext<'a, 'hir: 'a> {
 
     type_def_lifetime_params: DefIdMap<usize>,
 
-    current_hir_id_owner: Vec<(LocalDefId, u32)>,
+    current_hir_id_owner: (LocalDefId, u32),
     item_local_id_counters: NodeMap<u32>,
     node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
 
@@ -321,7 +321,7 @@ pub fn lower_crate<'a, 'hir>(
         anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
         type_def_lifetime_params: Default::default(),
         current_module: CRATE_DEF_ID,
-        current_hir_id_owner: vec![(CRATE_DEF_ID, 0)],
+        current_hir_id_owner: (CRATE_DEF_ID, 0),
         item_local_id_counters: Default::default(),
         node_id_to_hir_id: IndexVec::new(),
         generator_kind: None,
@@ -594,9 +594,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             .insert(owner, HIR_ID_COUNTER_LOCKED)
             .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
         let def_id = self.resolver.local_def_id(owner);
-        self.current_hir_id_owner.push((def_id, counter));
+        let old_owner = std::mem::replace(&mut self.current_hir_id_owner, (def_id, counter));
         let ret = f(self);
-        let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap();
+        let (new_def_id, new_counter) =
+            std::mem::replace(&mut self.current_hir_id_owner, old_owner);
 
         debug_assert!(def_id == new_def_id);
         debug_assert!(new_counter >= counter);
@@ -614,8 +615,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// properly. Calling the method twice with the same `NodeId` is fine though.
     fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
         self.lower_node_id_generic(ast_node_id, |this| {
-            let &mut (owner, ref mut local_id_counter) =
-                this.current_hir_id_owner.last_mut().unwrap();
+            let &mut (owner, ref mut local_id_counter) = &mut this.current_hir_id_owner;
             let local_id = *local_id_counter;
             *local_id_counter += 1;
             hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) }
@@ -868,10 +868,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // wouldn't have been added yet.
                     let generics = this.lower_generics_mut(
                         generics,
-                        ImplTraitContext::Universal(
-                            &mut params,
-                            this.current_hir_id_owner.last().unwrap().0,
-                        ),
+                        ImplTraitContext::Universal(&mut params, this.current_hir_id_owner.0),
                     );
                     let res = f(this, &mut params);
                     (params, (generics, res))
@@ -1077,7 +1074,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
             AssocTyConstraintKind::Bound { ref bounds } => {
                 let mut capturable_lifetimes;
-                let mut parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+                let mut parent_def_id = self.current_hir_id_owner.0;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
                 let (desugar_to_impl_trait, itctx) = match itctx {
                     // We are in the return position:
@@ -1198,7 +1195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                             // Construct a AnonConst where the expr is the "ty"'s path.
 
-                            let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+                            let parent_def_id = self.current_hir_id_owner.0;
                             let node_id = self.resolver.next_node_id();
 
                             // Add a definition for the in-band const def.
@@ -1814,10 +1811,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 if let Some((_, ibty)) = &mut in_band_ty_params {
                     this.lower_ty_direct(
                         &param.ty,
-                        ImplTraitContext::Universal(
-                            ibty,
-                            this.current_hir_id_owner.last().unwrap().0,
-                        ),
+                        ImplTraitContext::Universal(ibty, this.current_hir_id_owner.0),
                     )
                 } else {
                     this.lower_ty_direct(&param.ty, ImplTraitContext::disallowed())
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 79f35ad5819..5a4e7fd9d07 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -16,9 +16,19 @@ pub fn expand_deriving_eq(
     push: &mut dyn FnMut(Annotatable),
 ) {
     let inline = cx.meta_word(span, sym::inline);
+    let no_coverage_ident =
+        rustc_ast::attr::mk_nested_word_item(Ident::new(sym::no_coverage, span));
+    let no_coverage_feature =
+        rustc_ast::attr::mk_list_item(Ident::new(sym::feature, span), vec![no_coverage_ident]);
+    let no_coverage = cx.meta_word(span, sym::no_coverage);
     let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
     let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
-    let attrs = vec![cx.attribute(inline), cx.attribute(doc)];
+    let attrs = vec![
+        cx.attribute(inline),
+        cx.attribute(no_coverage_feature),
+        cx.attribute(no_coverage),
+        cx.attribute(doc),
+    ];
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 2ac516381cf..4d45e36c956 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -80,3 +80,10 @@ jobs:
       with:
         name: cg_clif-${{ runner.os }}
         path: cg_clif.tar.xz
+
+    - name: Upload prebuilt cg_clif (cross compile)
+      if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+      uses: actions/upload-artifact@v2
+      with:
+        name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
+        path: cg_clif.tar.xz
diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json
index 0cd576e160f..9009a532c54 100644
--- a/compiler/rustc_codegen_cranelift/.vscode/settings.json
+++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json
@@ -1,6 +1,6 @@
 {
     // source for rustc_* is not included in the rust-src component; disable the errors about this
-    "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "macro-error"],
+    "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
     "rust-analyzer.assist.importMergeBehavior": "last",
     "rust-analyzer.cargo.runBuildScripts": true,
     "rust-analyzer.linkedProjects": [
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index dc1cd336e15..e6792def567 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -39,16 +39,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "byteorder",
  "cranelift-bforest",
@@ -65,8 +65,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -74,18 +74,18 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -95,8 +95,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -113,8 +113,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -125,8 +125,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-codegen",
  "target-lexicon",
@@ -134,8 +134,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -306,6 +306,7 @@ dependencies = [
  "cranelift-frontend",
  "cranelift-jit",
  "cranelift-module",
+ "cranelift-native",
  "cranelift-object",
  "gimli",
  "indexmap",
@@ -334,9 +335,9 @@ dependencies = [
 
 [[package]]
 name = "target-lexicon"
-version = "0.11.2"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95"
+checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
 
 [[package]]
 name = "thiserror"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 60946ab2808..2789207c655 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -9,12 +9,13 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind", "x64"] }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
 cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
 cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
+cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
 cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
 cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-target-lexicon = "0.11.0"
+target-lexicon = "0.12.0"
 gimli = { version = "0.23.0", default-features = false, features = ["write"]}
 object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
@@ -28,6 +29,7 @@ smallvec = "1.6.1"
 #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
 #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
 #cranelift-module = { path = "../wasmtime/cranelift/module" }
+#cranelift-native = { path = ../wasmtime/cranelift/native" }
 #cranelift-jit = { path = "../wasmtime/cranelift/jit" }
 #cranelift-object = { path = "../wasmtime/cranelift/object" }
 
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index ffe1d9a1e65..08f9373be62 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -44,9 +44,10 @@ This will build your project with rustc_codegen_cranelift instead of the usual L
 
 For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md).
 
-## Env vars
+## Configuration
 
-See [env_vars.md](docs/env_vars.md) for all env vars used by rustc_codegen_cranelift.
+See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all
+configuration options.
 
 ## Not yet supported
 
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index 09c5d7590ab..e058a972ead 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -56,7 +56,7 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.39"
+version = "0.1.40"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -132,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.91"
+version = "0.2.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
+checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -167,6 +167,7 @@ dependencies = [
 name = "panic_abort"
 version = "0.0.0"
 dependencies = [
+ "alloc",
  "cfg-if",
  "compiler_builtins",
  "core",
@@ -242,11 +243,23 @@ dependencies = [
  "panic_abort",
  "panic_unwind",
  "rustc-demangle",
+ "std_detect",
  "unwind",
  "wasi",
 ]
 
 [[package]]
+name = "std_detect"
+version = "0.1.5"
+dependencies = [
+ "cfg-if",
+ "compiler_builtins",
+ "libc",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
 name = "sysroot"
 version = "0.0.0"
 dependencies = [
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
index c90205db0fb..f7fcef10774 100755
--- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
@@ -32,7 +32,7 @@ popd
 git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
 pushd compiler-builtins
 git checkout -- .
-git checkout 0.1.39
+git checkout 0.1.40
 git apply ../../crate_patches/000*-compiler-builtins-*.patch
 popd
 
diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
index e14768910a9..b4acc4f5b73 100644
--- a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
+++ b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
@@ -17,8 +17,8 @@ index 06054c8..3bea17b 100644
      fn wrapping_shr(self, other: u32) -> Self;
 -    fn rotate_left(self, other: u32) -> Self;
      fn overflowing_add(self, other: Self) -> (Self, bool);
-     fn aborting_div(self, other: Self) -> Self;
-     fn aborting_rem(self, other: Self) -> Self;
+     fn leading_zeros(self) -> u32;
+ }
 @@ -209,10 +208,6 @@ macro_rules! int_impl_common {
              <Self>::wrapping_shr(self, other)
          }
diff --git a/compiler/rustc_codegen_cranelift/docs/env_vars.md b/compiler/rustc_codegen_cranelift/docs/env_vars.md
deleted file mode 100644
index f7fde1b4f3a..00000000000
--- a/compiler/rustc_codegen_cranelift/docs/env_vars.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# List of env vars recognized by cg_clif
-
-<dl>
-    <dt>CG_CLIF_JIT_ARGS</dt>
-    <dd>When JIT mode is enable pass these arguments to the program.</dd>
-    <dt>CG_CLIF_INCR_CACHE_DISABLED</dt>
-    <dd>Don't cache object files in the incremental cache. Useful during development of cg_clif
-    to make it possible to use incremental mode for all analyses performed by rustc without caching
-    object files when their content should have been changed by a change to cg_clif.</dd>
-    <dt>CG_CLIF_DISPLAY_CG_TIME</dt>
-    <dd>If "1", display the time it took to perform codegen for a crate.</dd>
-    <dt>CG_CLIF_ENABLE_VERIFIER</dt>
-    <dd>Enable the Cranelift ir verifier for all compilation passes. If not set it will only run once
-    before passing the clif ir to Cranelift for compilation.</dt>
-</dl>
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index ea37ca98b59..6570f2bf9f2 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -11,6 +11,22 @@ unsafe extern "C" fn my_puts(s: *const i8) {
     puts(s);
 }
 
+macro_rules! assert {
+    ($e:expr) => {
+        if !$e {
+            panic(stringify!(! $e));
+        }
+    };
+}
+
+macro_rules! assert_eq {
+    ($l:expr, $r: expr) => {
+        if $l != $r {
+            panic(stringify!($l != $r));
+        }
+    }
+}
+
 #[lang = "termination"]
 trait Termination {
     fn report(self) -> i32;
@@ -20,8 +36,9 @@ impl Termination for () {
     fn report(self) -> i32 {
         unsafe {
             NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
-            *NUM_REF as i32
+            assert_eq!(*NUM_REF as i32, 44);
         }
+        0
     }
 }
 
@@ -82,29 +99,12 @@ fn start<T: Termination + 'static>(
         unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); }
     }
 
-    main().report();
-    0
+    main().report() as isize
 }
 
 static mut NUM: u8 = 6 * 7;
 static NUM_REF: &'static u8 = unsafe { &NUM };
 
-macro_rules! assert {
-    ($e:expr) => {
-        if !$e {
-            panic(stringify!(! $e));
-        }
-    };
-}
-
-macro_rules! assert_eq {
-    ($l:expr, $r: expr) => {
-        if $l != $r {
-            panic(stringify!($l != $r));
-        }
-    }
-}
-
 struct Unique<T: ?Sized> {
     pointer: *const T,
     _marker: PhantomData<T>,
@@ -296,6 +296,11 @@ fn main() {
     unsafe {
         global_asm_test();
     }
+
+    // Both statics have a reference that points to the same anonymous allocation.
+    static REF1: &u8 = &42;
+    static REF2: &u8 = REF1;
+    assert_eq!(*REF1, *REF2);
 }
 
 #[cfg(all(not(jit), target_os = "linux"))]
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index 015bbdfed46..77ba72df8ef 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -48,6 +48,8 @@ fn main() {
     assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
     println!("{}", 2.3f32.powf(2.0));
 
+    assert_eq!(i64::MAX.checked_mul(2), None);
+
     assert_eq!(-128i8, (-128i8).saturating_sub(1));
     assert_eq!(127i8, 127i8.saturating_sub(-128));
     assert_eq!(-128i8, (-128i8).saturating_add(-128));
@@ -84,6 +86,7 @@ fn main() {
     assert_eq!(houndred_i128 as f64, 100.0);
     assert_eq!(houndred_f32 as i128, 100);
     assert_eq!(houndred_f64 as i128, 100);
+    assert_eq!(1u128.rotate_left(2), 4);
 
     // Test signed 128bit comparing
     let max = usize::MAX as i128;
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 2917fc7ee39..5442e3345aa 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-03-29"
+channel = "nightly-2021-04-28"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
index 7971f620df1..3f98d77d76c 100644
--- a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
@@ -5,7 +5,7 @@
 set -e
 
 export CG_CLIF_DISPLAY_CG_TIME=1
-export CG_CLIF_INCR_CACHE_DISABLED=1
+export CG_CLIF_DISABLE_INCR_CACHE=1
 
 export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
 export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index e8bedf625f7..4821a07ac5d 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -45,7 +45,7 @@ index d95b5b7f17f..00b6f0e3635 100644
  [dependencies]
  core = { path = "../core" }
 -compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std', 'no-asm'] }
++compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] }
 
  [dev-dependencies]
  rand = "0.7"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index fbc3feceec7..347fb40e6f9 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -38,6 +38,7 @@ rm src/test/ui/threads-sendsync/task-stderr.rs
 rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs
 rm src/test/ui/drop/drop-trait-enum.rs
 rm src/test/ui/numbers-arithmetic/issue-8460.rs
+rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind
 
 rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
 rm src/test/ui/init-large-type.rs # same
@@ -47,6 +48,7 @@ rm src/test/ui/issues/issue-51947.rs # same
 rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
 rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
+rm src/test/ui/consts/issue-33537.rs # same
 rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
 rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
 rm src/test/ui/generator/size-moved-locals.rs # same
@@ -56,11 +58,13 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n
 
 rm src/test/incremental/hashes/inline_asm.rs # inline asm
 rm src/test/incremental/issue-72386.rs # same
-rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind
 rm src/test/incremental/issue-49482.rs # same
 rm src/test/incremental/issue-54059.rs # same
 rm src/test/incremental/lto.rs # requires lto
 
+rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
+rm -r src/test/run-make/unstable-flag-required # same
+
 rm src/test/pretty/asm.rs # inline asm
 rm src/test/pretty/raw-str-nonexpr.rs # same
 
@@ -68,6 +72,7 @@ rm -r src/test/run-pass-valgrind/unsized-locals
 
 rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning
 rm src/test/ui/json-bom-plus-crlf.rs # same
+rm src/test/ui/match/issue-82392.rs # differing error
 rm src/test/ui/type-alias-impl-trait/cross_crate_ice*.rs # requires removed aux dep
 
 rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 0e7829eaa26..54c8fb0e7b8 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -63,16 +63,16 @@ pub(crate) fn import_function<'tcx>(
     module: &mut dyn Module,
     inst: Instance<'tcx>,
 ) -> FuncId {
-    let name = tcx.symbol_name(inst).name.to_string();
+    let name = tcx.symbol_name(inst).name;
     let sig = get_function_sig(tcx, module.isa().triple(), inst);
-    module.declare_function(&name, Linkage::Import, &sig).unwrap()
+    module.declare_function(name, Linkage::Import, &sig).unwrap()
 }
 
 impl<'tcx> FunctionCx<'_, '_, 'tcx> {
     /// Instance must be monomorphized
     pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
-        let func_id = import_function(self.tcx, self.cx.module, inst);
-        let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func);
+        let func_id = import_function(self.tcx, self.module, inst);
+        let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
 
         if self.clif_comments.enabled() {
             self.add_comment(func_ref, format!("{:?}", inst));
@@ -89,8 +89,8 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         args: &[Value],
     ) -> &[Value] {
         let sig = Signature { params, returns, call_conv: CallConv::triple_default(self.triple()) };
-        let func_id = self.cx.module.declare_function(&name, Linkage::Import, &sig).unwrap();
-        let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func);
+        let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
+        let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
         let call_inst = self.bcx.ins().call(func_ref, args);
         if self.clif_comments.enabled() {
             self.add_comment(call_inst, format!("easy_call {}", name));
@@ -295,7 +295,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
 pub(crate) fn codegen_terminator_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     span: Span,
-    current_block: Block,
     func: &Operand<'tcx>,
     args: &[Operand<'tcx>],
     destination: Option<(Place<'tcx>, BasicBlock)>,
@@ -357,7 +356,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD))
         .unwrap_or(false);
     if is_cold {
-        fx.cold_blocks.insert(current_block);
+        // FIXME Mark current_block block as cold once Cranelift supports it
     }
 
     // Unpack arguments tuple for closures
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index f60645a9f97..a09e3257786 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -11,7 +11,7 @@ use rustc_span::symbol::sym;
 pub(crate) fn codegen(
     tcx: TyCtxt<'_>,
     module: &mut impl Module,
-    unwind_context: &mut UnwindContext<'_>,
+    unwind_context: &mut UnwindContext,
 ) -> bool {
     let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE).iter().any(|(_, list)| {
         use rustc_middle::middle::dependency_format::Linkage;
@@ -29,7 +29,7 @@ pub(crate) fn codegen(
 
 fn codegen_inner(
     module: &mut impl Module,
-    unwind_context: &mut UnwindContext<'_>,
+    unwind_context: &mut UnwindContext,
     kind: AllocatorKind,
 ) {
     let usize_ty = module.target_config().pointer_type();
diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs
index eb7927fc4ad..05c06bac27d 100644
--- a/compiler/rustc_codegen_cranelift/src/backend.rs
+++ b/compiler/rustc_codegen_cranelift/src/backend.rs
@@ -5,23 +5,23 @@ use std::convert::{TryFrom, TryInto};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_session::Session;
 
+use cranelift_codegen::isa::TargetIsa;
 use cranelift_module::FuncId;
+use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
 
 use object::write::*;
 use object::{RelocationEncoding, SectionKind, SymbolFlags};
 
-use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
-
 use gimli::SectionId;
 
 use crate::debuginfo::{DebugReloc, DebugRelocName};
 
 pub(crate) trait WriteMetadata {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
+    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
 }
 
 impl WriteMetadata for object::write::Object {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
+    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
         let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
         let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
         let offset = self.append_section_data(section_id, &data, 1);
@@ -113,7 +113,7 @@ impl WriteDebugInfo for ObjectProduct {
 }
 
 pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
-    let triple = crate::build_isa(sess).triple().clone();
+    let triple = crate::target_triple(sess);
 
     let binary_format = match triple.binary_format {
         target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
@@ -141,13 +141,9 @@ pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object
     metadata_object.write().unwrap()
 }
 
-pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
-    let mut builder = ObjectBuilder::new(
-        crate::build_isa(sess),
-        name + ".o",
-        cranelift_module::default_libcall_names(),
-    )
-    .unwrap();
+pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
+    let mut builder =
+        ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
     // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
     // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
     // can easily double the amount of time necessary to perform linking.
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index b34a29c25b9..3ec5c14ff17 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -6,9 +6,14 @@ use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::layout::FnAbiExt;
 use rustc_target::abi::call::FnAbi;
 
+use crate::constant::ConstantCx;
 use crate::prelude::*;
 
-pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) {
+pub(crate) fn codegen_fn<'tcx>(
+    cx: &mut crate::CodegenCx<'tcx>,
+    module: &mut dyn Module,
+    instance: Instance<'tcx>,
+) {
     let tcx = cx.tcx;
 
     let _inst_guard =
@@ -18,9 +23,9 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     let mir = tcx.instance_mir(instance.def);
 
     // Declare function
-    let name = tcx.symbol_name(instance).name.to_string();
-    let sig = get_function_sig(tcx, cx.module.isa().triple(), instance);
-    let func_id = cx.module.declare_function(&name, Linkage::Local, &sig).unwrap();
+    let symbol_name = tcx.symbol_name(instance);
+    let sig = get_function_sig(tcx, module.isa().triple(), instance);
+    let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap();
 
     cx.cached_context.clear();
 
@@ -39,15 +44,19 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
         (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
 
     // Make FunctionCx
-    let pointer_type = cx.module.target_config().pointer_type();
+    let pointer_type = module.target_config().pointer_type();
     let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
 
     let mut fx = FunctionCx {
         cx,
+        module,
         tcx,
         pointer_type,
+        vtables: FxHashMap::default(),
+        constants_cx: ConstantCx::new(),
 
         instance,
+        symbol_name,
         mir,
         fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
 
@@ -55,7 +64,6 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
         block_map,
         local_map: IndexVec::with_capacity(mir.local_decls.len()),
         caller_location: None, // set by `codegen_fn_prelude`
-        cold_blocks: EntitySet::new(),
 
         clif_comments,
         source_info_set: indexmap::IndexSet::new(),
@@ -90,7 +98,8 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     let mut clif_comments = fx.clif_comments;
     let source_info_set = fx.source_info_set;
     let local_map = fx.local_map;
-    let cold_blocks = fx.cold_blocks;
+
+    fx.constants_cx.finalize(fx.tcx, &mut *fx.module);
 
     // Store function in context
     let context = &mut cx.cached_context;
@@ -103,21 +112,15 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
 
     // Perform rust specific optimizations
     tcx.sess.time("optimize clif ir", || {
-        crate::optimize::optimize_function(
-            tcx,
-            instance,
-            context,
-            &cold_blocks,
-            &mut clif_comments,
-        );
+        crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
     });
 
     // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
     // instruction, which doesn't have an encoding.
     context.compute_cfg();
     context.compute_domtree();
-    context.eliminate_unreachable_code(cx.module.isa()).unwrap();
-    context.dce(cx.module.isa()).unwrap();
+    context.eliminate_unreachable_code(module.isa()).unwrap();
+    context.dce(module.isa()).unwrap();
     // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
     // invalidate it when it would change.
     context.domtree.clear();
@@ -125,7 +128,6 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
 
     // Define function
-    let module = &mut cx.module;
     tcx.sess.time("define function", || {
         module
             .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
@@ -136,7 +138,7 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     crate::pretty_clif::write_clif_file(
         tcx,
         "opt",
-        Some(cx.module.isa()),
+        Some(module.isa()),
         instance,
         &context,
         &clif_comments,
@@ -145,13 +147,13 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm {
         crate::pretty_clif::write_ir_file(
             tcx,
-            &format!("{}.vcode", tcx.symbol_name(instance).name),
+            || format!("{}.vcode", tcx.symbol_name(instance).name),
             |file| file.write_all(disasm.as_bytes()),
         )
     }
 
     // Define debuginfo for function
-    let isa = cx.module.isa();
+    let isa = module.isa();
     let debug_context = &mut cx.debug_context;
     let unwind_context = &mut cx.unwind_context;
     tcx.sess.time("generate debug info", || {
@@ -159,7 +161,7 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
             debug_context.define_function(
                 instance,
                 func_id,
-                &name,
+                symbol_name.name,
                 isa,
                 context,
                 &source_info_set,
@@ -205,9 +207,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
             // Unwinding after panicking is not supported
             continue;
 
-            // FIXME once unwinding is supported uncomment next lines
-            // // Unwinding is unlikely to happen, so mark cleanup block's as cold.
-            // fx.cold_blocks.insert(block);
+            // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do
+            // so for cleanup blocks.
         }
 
         fx.bcx.ins().nop();
@@ -262,7 +263,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
 
                 let target = fx.get_block(*target);
                 let failure = fx.bcx.create_block();
-                fx.cold_blocks.insert(failure);
+                // FIXME Mark failure block as cold once Cranelift supports it
 
                 if *expected {
                     fx.bcx.ins().brz(cond, failure, &[]);
@@ -355,14 +356,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
                 from_hir_call: _,
             } => {
                 fx.tcx.sess.time("codegen call", || {
-                    crate::abi::codegen_terminator_call(
-                        fx,
-                        *fn_span,
-                        block,
-                        func,
-                        args,
-                        *destination,
-                    )
+                    crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
                 });
             }
             TerminatorKind::InlineAsm {
@@ -664,7 +658,7 @@ fn codegen_stmt<'tcx>(
                         // FIXME use emit_small_memset where possible
                         let addr = lval.to_ptr().get_addr(fx);
                         let val = operand.load_scalar(fx);
-                        fx.bcx.call_memset(fx.cx.module.target_config(), addr, val, times);
+                        fx.bcx.call_memset(fx.module.target_config(), addr, val, times);
                     } else {
                         let loop_block = fx.bcx.create_block();
                         let loop_block2 = fx.bcx.create_block();
@@ -750,85 +744,15 @@ fn codegen_stmt<'tcx>(
         | StatementKind::AscribeUserType(..) => {}
 
         StatementKind::LlvmInlineAsm(asm) => {
-            use rustc_span::symbol::Symbol;
-            let LlvmInlineAsm { asm, outputs, inputs } = &**asm;
-            let rustc_hir::LlvmInlineAsmInner {
-                asm: asm_code,         // Name
-                outputs: output_names, // Vec<LlvmInlineAsmOutput>
-                inputs: input_names,   // Vec<Name>
-                clobbers,              // Vec<Name>
-                volatile,              // bool
-                alignstack,            // bool
-                dialect: _,
-                asm_str_style: _,
-            } = asm;
-            match asm_code.as_str().trim() {
+            match asm.asm.asm.as_str().trim() {
                 "" => {
                     // Black box
                 }
-                "mov %rbx, %rsi\n                  cpuid\n                  xchg %rbx, %rsi" => {
-                    assert_eq!(input_names, &[Symbol::intern("{eax}"), Symbol::intern("{ecx}")]);
-                    assert_eq!(output_names.len(), 4);
-                    for (i, c) in (&["={eax}", "={esi}", "={ecx}", "={edx}"]).iter().enumerate() {
-                        assert_eq!(&output_names[i].constraint.as_str(), c);
-                        assert!(!output_names[i].is_rw);
-                        assert!(!output_names[i].is_indirect);
-                    }
-
-                    assert_eq!(clobbers, &[]);
-
-                    assert!(!volatile);
-                    assert!(!alignstack);
-
-                    assert_eq!(inputs.len(), 2);
-                    let leaf = codegen_operand(fx, &inputs[0].1).load_scalar(fx); // %eax
-                    let subleaf = codegen_operand(fx, &inputs[1].1).load_scalar(fx); // %ecx
-
-                    let (eax, ebx, ecx, edx) =
-                        crate::intrinsics::codegen_cpuid_call(fx, leaf, subleaf);
-
-                    assert_eq!(outputs.len(), 4);
-                    codegen_place(fx, outputs[0])
-                        .write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
-                    codegen_place(fx, outputs[1])
-                        .write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
-                    codegen_place(fx, outputs[2])
-                        .write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
-                    codegen_place(fx, outputs[3])
-                        .write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
-                }
-                "xgetbv" => {
-                    assert_eq!(input_names, &[Symbol::intern("{ecx}")]);
-
-                    assert_eq!(output_names.len(), 2);
-                    for (i, c) in (&["={eax}", "={edx}"]).iter().enumerate() {
-                        assert_eq!(&output_names[i].constraint.as_str(), c);
-                        assert!(!output_names[i].is_rw);
-                        assert!(!output_names[i].is_indirect);
-                    }
-
-                    assert_eq!(clobbers, &[]);
-
-                    assert!(!volatile);
-                    assert!(!alignstack);
-
-                    crate::trap::trap_unimplemented(fx, "_xgetbv arch intrinsic is not supported");
-                }
-                // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
-                _ if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") => {
-                    crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
-                }
-                _ if fx.tcx.symbol_name(fx.instance).name == "__alloca" => {
-                    crate::trap::trap_unimplemented(fx, "Alloca is not supported");
-                }
-                // Used in sys::windows::abort_internal
-                "int $$0x29" => {
-                    crate::trap::trap_unimplemented(fx, "Windows abort");
-                }
-                _ => fx
-                    .tcx
-                    .sess
-                    .span_fatal(stmt.source_info.span, "Inline assembly is not supported"),
+                _ => fx.tcx.sess.span_fatal(
+                    stmt.source_info.span,
+                    "Legacy `llvm_asm!` inline assembly is not supported. \
+                    Try using the new `asm!` instead.",
+                ),
             }
         }
         StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
@@ -844,7 +768,7 @@ fn codegen_stmt<'tcx>(
             let elem_size: u64 = pointee.size.bytes();
             let bytes =
                 if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
-            fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, bytes);
+            fx.bcx.call_memcpy(fx.module.target_config(), dst, src, bytes);
         }
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index b5874f62535..92e4435565e 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -1,8 +1,10 @@
 use rustc_index::vec::IndexVec;
+use rustc_middle::ty::SymbolName;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{Integer, Primitive};
 use rustc_target::spec::{HasTargetSpec, Target};
 
+use crate::constant::ConstantCx;
 use crate::prelude::*;
 
 pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
@@ -226,12 +228,16 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool {
     }
 }
 
-pub(crate) struct FunctionCx<'m, 'clif, 'tcx> {
-    pub(crate) cx: &'clif mut crate::CodegenCx<'m, 'tcx>,
+pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
+    pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>,
+    pub(crate) module: &'m mut dyn Module,
     pub(crate) tcx: TyCtxt<'tcx>,
     pub(crate) pointer_type: Type, // Cached from module
+    pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
+    pub(crate) constants_cx: ConstantCx,
 
     pub(crate) instance: Instance<'tcx>,
+    pub(crate) symbol_name: SymbolName<'tcx>,
     pub(crate) mir: &'tcx Body<'tcx>,
     pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>,
 
@@ -242,9 +248,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx> {
     /// When `#[track_caller]` is used, the implicit caller location is stored in this variable.
     pub(crate) caller_location: Option<CValue<'tcx>>,
 
-    /// See [`crate::optimize::code_layout`] for more information.
-    pub(crate) cold_blocks: EntitySet<Block>,
-
     pub(crate) clif_comments: crate::pretty_clif::CommentWriter,
     pub(crate) source_info_set: indexmap::IndexSet<SourceInfo>,
 
@@ -339,7 +342,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
     }
 
     pub(crate) fn triple(&self) -> &target_lexicon::Triple {
-        self.cx.module.isa().triple()
+        self.module.isa().triple()
     }
 
     pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
@@ -352,15 +355,14 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         let mut data_ctx = DataContext::new();
         data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
         let msg_id = self
-            .cx
             .module
             .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false)
             .unwrap();
 
         // Ignore DuplicateDefinition error, as the data will be the same
-        let _ = self.cx.module.define_data(msg_id, &data_ctx);
+        let _ = self.module.define_data(msg_id, &data_ctx);
 
-        let local_msg_id = self.cx.module.declare_data_in_func(msg_id, self.bcx.func);
+        let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func);
         if self.clif_comments.enabled() {
             self.add_comment(local_msg_id, msg);
         }
diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs
new file mode 100644
index 00000000000..e59a0cb0a23
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/src/config.rs
@@ -0,0 +1,107 @@
+use std::env;
+use std::str::FromStr;
+
+fn bool_env_var(key: &str) -> bool {
+    env::var(key).as_ref().map(|val| &**val) == Ok("1")
+}
+
+/// The mode to use for compilation.
+#[derive(Copy, Clone, Debug)]
+pub enum CodegenMode {
+    /// AOT compile the crate. This is the default.
+    Aot,
+    /// JIT compile and execute the crate.
+    Jit,
+    /// JIT compile and execute the crate, but only compile functions the first time they are used.
+    JitLazy,
+}
+
+impl FromStr for CodegenMode {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "aot" => Ok(CodegenMode::Aot),
+            "jit" => Ok(CodegenMode::Jit),
+            "jit-lazy" => Ok(CodegenMode::JitLazy),
+            _ => Err(format!("Unknown codegen mode `{}`", s)),
+        }
+    }
+}
+
+/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars.
+#[derive(Clone, Debug)]
+pub struct BackendConfig {
+    /// Should the crate be AOT compiled or JIT executed.
+    ///
+    /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`.
+    pub codegen_mode: CodegenMode,
+
+    /// When JIT mode is enable pass these arguments to the program.
+    ///
+    /// Defaults to the value of `CG_CLIF_JIT_ARGS`.
+    pub jit_args: Vec<String>,
+
+    /// Display the time it took to perform codegen for a crate.
+    ///
+    /// Defaults to true when the `CG_CLIF_DISPLAY_CG_TIME` env var is set to 1 or false otherwise.
+    /// Can be set using `-Cllvm-args=display_cg_time=...`.
+    pub display_cg_time: bool,
+
+    /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
+    /// once before passing the clif ir to Cranelift for compilation.
+    ///
+    /// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is
+    /// compiled with debug assertions enabled or false otherwise. Can be set using
+    /// `-Cllvm-args=enable_verifier=...`.
+    pub enable_verifier: bool,
+
+    /// Don't cache object files in the incremental cache. Useful during development of cg_clif
+    /// to make it possible to use incremental mode for all analyses performed by rustc without
+    /// caching object files when their content should have been changed by a change to cg_clif.
+    ///
+    /// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false
+    /// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`.
+    pub disable_incr_cache: bool,
+}
+
+impl Default for BackendConfig {
+    fn default() -> Self {
+        BackendConfig {
+            codegen_mode: CodegenMode::Aot,
+            jit_args: {
+                let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
+                args.split(' ').map(|arg| arg.to_string()).collect()
+            },
+            display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
+            enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
+            disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
+        }
+    }
+}
+
+impl BackendConfig {
+    /// Parse the configuration passed in using `-Cllvm-args`.
+    pub fn from_opts(opts: &[String]) -> Result<Self, String> {
+        fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
+            value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name))
+        }
+
+        let mut config = BackendConfig::default();
+        for opt in opts {
+            if let Some((name, value)) = opt.split_once('=') {
+                match name {
+                    "mode" => config.codegen_mode = value.parse()?,
+                    "display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
+                    "enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
+                    "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
+                    _ => return Err(format!("Unknown option `{}`", name)),
+                }
+            } else {
+                return Err(format!("Invalid option `{}`", opt));
+            }
+        }
+
+        Ok(config)
+    }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index fcd41c84465..0a0e02d2639 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -2,7 +2,7 @@
 
 use rustc_span::DUMMY_SP;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::ErrorReported;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{
@@ -15,10 +15,10 @@ use cranelift_module::*;
 
 use crate::prelude::*;
 
-#[derive(Default)]
 pub(crate) struct ConstantCx {
     todo: Vec<TodoItem>,
     done: FxHashSet<DataId>,
+    anon_allocs: FxHashMap<AllocId, DataId>,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -28,6 +28,10 @@ enum TodoItem {
 }
 
 impl ConstantCx {
+    pub(crate) fn new() -> Self {
+        ConstantCx { todo: vec![], done: FxHashSet::default(), anon_allocs: FxHashMap::default() }
+    }
+
     pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
         //println!("todo {:?}", self.todo);
         define_all_allocs(tcx, module, &mut self);
@@ -74,8 +78,10 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
     all_constants_ok
 }
 
-pub(crate) fn codegen_static(constants_cx: &mut ConstantCx, def_id: DefId) {
+pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
+    let mut constants_cx = ConstantCx::new();
     constants_cx.todo.push(TodoItem::Static(def_id));
+    constants_cx.finalize(tcx, module);
 }
 
 pub(crate) fn codegen_tls_ref<'tcx>(
@@ -83,8 +89,8 @@ pub(crate) fn codegen_tls_ref<'tcx>(
     def_id: DefId,
     layout: TyAndLayout<'tcx>,
 ) -> CValue<'tcx> {
-    let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(local_data_id, format!("tls {:?}", def_id));
     }
@@ -97,8 +103,8 @@ fn codegen_static_ref<'tcx>(
     def_id: DefId,
     layout: TyAndLayout<'tcx>,
 ) -> CPlace<'tcx> {
-    let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(local_data_id, format!("{:?}", def_id));
     }
@@ -182,28 +188,31 @@ pub(crate) fn codegen_const_value<'tcx>(
                     let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id);
                     let base_addr = match alloc_kind {
                         Some(GlobalAlloc::Memory(alloc)) => {
-                            fx.cx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
-                            let data_id =
-                                data_id_for_alloc_id(fx.cx.module, ptr.alloc_id, alloc.mutability);
+                            fx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
+                            let data_id = data_id_for_alloc_id(
+                                &mut fx.constants_cx,
+                                fx.module,
+                                ptr.alloc_id,
+                                alloc.mutability,
+                            );
                             let local_data_id =
-                                fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+                                fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
                             if fx.clif_comments.enabled() {
                                 fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id));
                             }
                             fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
                         }
                         Some(GlobalAlloc::Function(instance)) => {
-                            let func_id =
-                                crate::abi::import_function(fx.tcx, fx.cx.module, instance);
+                            let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
                             let local_func_id =
-                                fx.cx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
+                                fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
                             fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
                         }
                         Some(GlobalAlloc::Static(def_id)) => {
                             assert!(fx.tcx.is_static(def_id));
-                            let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
+                            let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
                             let local_data_id =
-                                fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+                                fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
                             if fx.clif_comments.enabled() {
                                 fx.add_comment(local_data_id, format!("{:?}", def_id));
                             }
@@ -243,10 +252,11 @@ fn pointer_for_allocation<'tcx>(
     alloc: &'tcx Allocation,
 ) -> crate::pointer::Pointer {
     let alloc_id = fx.tcx.create_memory_alloc(alloc);
-    fx.cx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
-    let data_id = data_id_for_alloc_id(fx.cx.module, alloc_id, alloc.mutability);
+    fx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
+    let data_id =
+        data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
 
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(local_data_id, format!("{:?}", alloc_id));
     }
@@ -255,18 +265,14 @@ fn pointer_for_allocation<'tcx>(
 }
 
 fn data_id_for_alloc_id(
+    cx: &mut ConstantCx,
     module: &mut dyn Module,
     alloc_id: AllocId,
     mutability: rustc_hir::Mutability,
 ) -> DataId {
-    module
-        .declare_data(
-            &format!(".L__alloc_{:x}", alloc_id.0),
-            Linkage::Local,
-            mutability == rustc_hir::Mutability::Mut,
-            false,
-        )
-        .unwrap()
+    *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
+        module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap()
+    })
 }
 
 fn data_id_for_static(
@@ -344,7 +350,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                     GlobalAlloc::Memory(alloc) => alloc,
                     GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(),
                 };
-                let data_id = data_id_for_alloc_id(module, alloc_id, alloc.mutability);
+                let data_id = data_id_for_alloc_id(cx, module, alloc_id, alloc.mutability);
                 (data_id, alloc, None)
             }
             TodoItem::Static(def_id) => {
@@ -397,7 +403,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 }
                 GlobalAlloc::Memory(target_alloc) => {
                     cx.todo.push(TodoItem::Alloc(reloc));
-                    data_id_for_alloc_id(module, reloc, target_alloc.mutability)
+                    data_id_for_alloc_id(cx, module, reloc, target_alloc.mutability)
                 }
                 GlobalAlloc::Static(def_id) => {
                     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
@@ -419,8 +425,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
             data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
         }
 
-        // FIXME don't duplicate definitions in lazy jit mode
-        let _ = module.define_data(data_id, &data_ctx);
+        module.define_data(data_id, &data_ctx).unwrap();
         cx.done.insert(data_id);
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index 357c9fe6ed8..d1251e749f3 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -5,17 +5,19 @@ use crate::prelude::*;
 use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
 
 use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
+use gimli::RunTimeEndian;
 
 use crate::backend::WriteDebugInfo;
 
-pub(crate) struct UnwindContext<'tcx> {
-    tcx: TyCtxt<'tcx>,
+pub(crate) struct UnwindContext {
+    endian: RunTimeEndian,
     frame_table: FrameTable,
     cie_id: Option<CieId>,
 }
 
-impl<'tcx> UnwindContext<'tcx> {
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
+impl UnwindContext {
+    pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
+        let endian = super::target_endian(tcx);
         let mut frame_table = FrameTable::default();
 
         let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
@@ -28,7 +30,7 @@ impl<'tcx> UnwindContext<'tcx> {
             None
         };
 
-        UnwindContext { tcx, frame_table, cie_id }
+        UnwindContext { endian, frame_table, cie_id }
     }
 
     pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
@@ -54,8 +56,7 @@ impl<'tcx> UnwindContext<'tcx> {
     }
 
     pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
-        let mut eh_frame =
-            EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx)));
+        let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
         self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 
         if !eh_frame.0.writer.slice().is_empty() {
@@ -70,17 +71,16 @@ impl<'tcx> UnwindContext<'tcx> {
         }
     }
 
-    #[cfg(feature = "jit")]
-    pub(crate) unsafe fn register_jit(
-        self,
-        jit_module: &cranelift_jit::JITModule,
-    ) -> Option<UnwindRegistry> {
-        let mut eh_frame =
-            EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx)));
+    #[cfg(all(feature = "jit", windows))]
+    pub(crate) unsafe fn register_jit(self, _jit_module: &cranelift_jit::JITModule) {}
+
+    #[cfg(all(feature = "jit", not(windows)))]
+    pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) {
+        let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
         self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 
         if eh_frame.0.writer.slice().is_empty() {
-            return None;
+            return;
         }
 
         let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module);
@@ -88,7 +88,10 @@ impl<'tcx> UnwindContext<'tcx> {
         // GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
         eh_frame.extend(&[0, 0, 0, 0]);
 
-        let mut registrations = Vec::new();
+        // FIXME support unregistering unwind tables once cranelift-jit supports deallocating
+        // individual functions
+        #[allow(unused_variables)]
+        let (eh_frame, eh_frame_len, _) = Vec::into_raw_parts(eh_frame);
 
         // =======================================================================
         // Everything after this line up to the end of the file is loosly based on
@@ -96,8 +99,8 @@ impl<'tcx> UnwindContext<'tcx> {
         #[cfg(target_os = "macos")]
         {
             // On macOS, `__register_frame` takes a pointer to a single FDE
-            let start = eh_frame.as_ptr();
-            let end = start.add(eh_frame.len());
+            let start = eh_frame;
+            let end = start.add(eh_frame_len);
             let mut current = start;
 
             // Walk all of the entries in the frame table and register them
@@ -107,7 +110,6 @@ impl<'tcx> UnwindContext<'tcx> {
                 // Skip over the CIE
                 if current != start {
                     __register_frame(current);
-                    registrations.push(current as usize);
                 }
 
                 // Move to the next table entry (+4 because the length itself is not inclusive)
@@ -117,41 +119,12 @@ impl<'tcx> UnwindContext<'tcx> {
         #[cfg(not(target_os = "macos"))]
         {
             // On other platforms, `__register_frame` will walk the FDEs until an entry of length 0
-            let ptr = eh_frame.as_ptr();
-            __register_frame(ptr);
-            registrations.push(ptr as usize);
+            __register_frame(eh_frame);
         }
-
-        Some(UnwindRegistry { _frame_table: eh_frame, registrations })
     }
 }
 
-/// Represents a registry of function unwind information for System V ABI.
-pub(crate) struct UnwindRegistry {
-    _frame_table: Vec<u8>,
-    registrations: Vec<usize>,
-}
-
 extern "C" {
     // libunwind import
     fn __register_frame(fde: *const u8);
-    fn __deregister_frame(fde: *const u8);
-}
-
-impl Drop for UnwindRegistry {
-    fn drop(&mut self) {
-        unsafe {
-            // libgcc stores the frame entries as a linked list in decreasing sort order
-            // based on the PC value of the registered entry.
-            //
-            // As we store the registrations in increasing order, it would be O(N^2) to
-            // deregister in that order.
-            //
-            // To ensure that we just pop off the first element in the list upon every
-            // deregistration, walk our list of registrations backwards.
-            for fde in self.registrations.iter().rev() {
-                __deregister_frame(*fde as *const _);
-            }
-        }
-    }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index ed3bdedddce..9c5cd53d866 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -16,12 +16,6 @@ use cranelift_object::ObjectModule;
 
 use crate::{prelude::*, BackendConfig};
 
-fn new_module(tcx: TyCtxt<'_>, name: String) -> ObjectModule {
-    let module = crate::backend::make_module(tcx.sess, name);
-    assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
-    module
-}
-
 struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
 
 impl<HCX> HashStable<HCX> for ModuleCodegenResult {
@@ -32,11 +26,12 @@ impl<HCX> HashStable<HCX> for ModuleCodegenResult {
 
 fn emit_module(
     tcx: TyCtxt<'_>,
+    backend_config: &BackendConfig,
     name: String,
     kind: ModuleKind,
     module: ObjectModule,
     debug: Option<DebugContext<'_>>,
-    unwind_context: UnwindContext<'_>,
+    unwind_context: UnwindContext,
 ) -> ModuleCodegenResult {
     let mut product = module.finish();
 
@@ -52,7 +47,7 @@ fn emit_module(
         tcx.sess.fatal(&format!("error writing object file: {}", err));
     }
 
-    let work_product = if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() {
+    let work_product = if backend_config.disable_incr_cache {
         None
     } else {
         rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
@@ -110,23 +105,24 @@ fn module_codegen(
     let cgu = tcx.codegen_unit(cgu_name);
     let mono_items = cgu.items_in_deterministic_order(tcx);
 
-    let mut module = new_module(tcx, cgu_name.as_str().to_string());
+    let isa = crate::build_isa(tcx.sess, &backend_config);
+    let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string());
 
     let mut cx = crate::CodegenCx::new(
         tcx,
-        backend_config,
-        &mut module,
+        backend_config.clone(),
+        module.isa(),
         tcx.sess.opts.debuginfo != DebugInfo::None,
     );
-    super::predefine_mono_items(&mut cx, &mono_items);
+    super::predefine_mono_items(tcx, &mut module, &mono_items);
     for (mono_item, _) in mono_items {
         match mono_item {
             MonoItem::Fn(inst) => {
-                cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst));
-            }
-            MonoItem::Static(def_id) => {
-                crate::constant::codegen_static(&mut cx.constants_cx, def_id)
+                cx.tcx
+                    .sess
+                    .time("codegen fn", || crate::base::codegen_fn(&mut cx, &mut module, inst));
             }
+            MonoItem::Static(def_id) => crate::constant::codegen_static(tcx, &mut module, def_id),
             MonoItem::GlobalAsm(item_id) => {
                 let item = cx.tcx.hir().item(item_id);
                 if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
@@ -138,25 +134,28 @@ fn module_codegen(
             }
         }
     }
-    let (global_asm, debug, mut unwind_context) =
-        tcx.sess.time("finalize CodegenCx", || cx.finalize());
-    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context);
+    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false);
 
-    let codegen_result = emit_module(
-        tcx,
-        cgu.name().as_str().to_string(),
-        ModuleKind::Regular,
-        module,
-        debug,
-        unwind_context,
-    );
+    let debug_context = cx.debug_context;
+    let unwind_context = cx.unwind_context;
+    let codegen_result = tcx.sess.time("write object file", || {
+        emit_module(
+            tcx,
+            &backend_config,
+            cgu.name().as_str().to_string(),
+            ModuleKind::Regular,
+            module,
+            debug_context,
+            unwind_context,
+        )
+    });
 
-    codegen_global_asm(tcx, &cgu.name().as_str(), &global_asm);
+    codegen_global_asm(tcx, &cgu.name().as_str(), &cx.global_asm);
 
     codegen_result
 }
 
-pub(super) fn run_aot(
+pub(crate) fn run_aot(
     tcx: TyCtxt<'_>,
     backend_config: BackendConfig,
     metadata: EncodedMetadata,
@@ -193,14 +192,14 @@ pub(super) fn run_aot(
         }
     }
 
-    let modules = super::time(tcx, "codegen mono items", || {
+    let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
         cgus.iter()
             .map(|cgu| {
                 let cgu_reuse = determine_cgu_reuse(tcx, cgu);
                 tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
 
                 match cgu_reuse {
-                    _ if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() => {}
+                    _ if backend_config.disable_incr_cache => {}
                     CguReuse::No => {}
                     CguReuse::PreLto => {
                         return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products);
@@ -212,7 +211,7 @@ pub(super) fn run_aot(
                 let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task(
                     dep_node,
                     tcx,
-                    (backend_config, cgu.name()),
+                    (backend_config.clone(), cgu.name()),
                     module_codegen,
                     rustc_middle::dep_graph::hash_result,
                 );
@@ -228,7 +227,10 @@ pub(super) fn run_aot(
 
     tcx.sess.abort_if_errors();
 
-    let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
+    let isa = crate::build_isa(tcx.sess, &backend_config);
+    let mut allocator_module =
+        crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string());
+    assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
     let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
     let created_alloc_shim =
         crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
@@ -236,6 +238,7 @@ pub(super) fn run_aot(
     let allocator_module = if created_alloc_shim {
         let ModuleCodegenResult(module, work_product) = emit_module(
             tcx,
+            &backend_config,
             "allocator_shim".to_string(),
             ModuleKind::Allocator,
             allocator_module,
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index dbe1ff083f0..53c93f6a9dd 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -1,4 +1,4 @@
-//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
+//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object
 //! files.
 
 use std::cell::RefCell;
@@ -15,25 +15,56 @@ use cranelift_jit::{JITBuilder, JITModule};
 use crate::{prelude::*, BackendConfig};
 use crate::{CodegenCx, CodegenMode};
 
-thread_local! {
-    pub static BACKEND_CONFIG: RefCell<Option<BackendConfig>> = RefCell::new(None);
-    pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None);
+struct JitState {
+    backend_config: BackendConfig,
+    jit_module: JITModule,
 }
 
-pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
-    if !tcx.sess.opts.output_types.should_codegen() {
-        tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
-    }
+thread_local! {
+    static LAZY_JIT_STATE: RefCell<Option<JitState>> = RefCell::new(None);
+}
 
+fn create_jit_module<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    backend_config: &BackendConfig,
+    hotswap: bool,
+) -> (JITModule, CodegenCx<'tcx>) {
     let imported_symbols = load_imported_symbols_for_jit(tcx);
 
-    let mut jit_builder =
-        JITBuilder::with_isa(crate::build_isa(tcx.sess), cranelift_module::default_libcall_names());
-    jit_builder.hotswap(matches!(backend_config.codegen_mode, CodegenMode::JitLazy));
+    let isa = crate::build_isa(tcx.sess, backend_config);
+    let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
+    jit_builder.hotswap(hotswap);
     crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
     jit_builder.symbols(imported_symbols);
     let mut jit_module = JITModule::new(jit_builder);
-    assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
+
+    let mut cx = crate::CodegenCx::new(tcx, backend_config.clone(), jit_module.isa(), false);
+
+    crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
+    crate::main_shim::maybe_create_entry_wrapper(
+        tcx,
+        &mut jit_module,
+        &mut cx.unwind_context,
+        true,
+    );
+
+    (jit_module, cx)
+}
+
+pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
+    if !tcx.sess.opts.output_types.should_codegen() {
+        tcx.sess.fatal("JIT mode doesn't work with `cargo check`");
+    }
+
+    if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) {
+        tcx.sess.fatal("can't jit non-executable crate");
+    }
+
+    let (mut jit_module, mut cx) = create_jit_module(
+        tcx,
+        &backend_config,
+        matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
+    );
 
     let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
     let mono_items = cgus
@@ -44,52 +75,45 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
         .into_iter()
         .collect::<Vec<(_, (_, _))>>();
 
-    let mut cx = crate::CodegenCx::new(tcx, backend_config, &mut jit_module, false);
-
-    super::time(tcx, "codegen mono items", || {
-        super::predefine_mono_items(&mut cx, &mono_items);
+    super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
+        super::predefine_mono_items(tcx, &mut jit_module, &mono_items);
         for (mono_item, _) in mono_items {
             match mono_item {
                 MonoItem::Fn(inst) => match backend_config.codegen_mode {
                     CodegenMode::Aot => unreachable!(),
                     CodegenMode::Jit => {
-                        cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst));
+                        cx.tcx.sess.time("codegen fn", || {
+                            crate::base::codegen_fn(&mut cx, &mut jit_module, inst)
+                        });
                     }
-                    CodegenMode::JitLazy => codegen_shim(&mut cx, inst),
+                    CodegenMode::JitLazy => codegen_shim(&mut cx, &mut jit_module, inst),
                 },
                 MonoItem::Static(def_id) => {
-                    crate::constant::codegen_static(&mut cx.constants_cx, def_id);
+                    crate::constant::codegen_static(tcx, &mut jit_module, def_id);
                 }
                 MonoItem::GlobalAsm(item_id) => {
-                    let item = cx.tcx.hir().item(item_id);
+                    let item = tcx.hir().item(item_id);
                     tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode");
                 }
             }
         }
     });
 
-    let (global_asm, _debug, mut unwind_context) =
-        tcx.sess.time("finalize CodegenCx", || cx.finalize());
-    jit_module.finalize_definitions();
-
-    if !global_asm.is_empty() {
+    if !cx.global_asm.is_empty() {
         tcx.sess.fatal("Inline asm is not supported in JIT mode");
     }
 
-    crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
-
     tcx.sess.abort_if_errors();
 
     jit_module.finalize_definitions();
-    let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_module) };
+    unsafe { cx.unwind_context.register_jit(&jit_module) };
 
     println!(
         "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed"
     );
 
-    let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
     let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
-        .chain(args.split(' '))
+        .chain(backend_config.jit_args.iter().map(|arg| &**arg))
         .map(|arg| CString::new(arg).unwrap())
         .collect::<Vec<_>>();
     let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
@@ -98,61 +122,27 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
     // useful as some dynamic linkers use it as a marker to jump over.
     argv.push(std::ptr::null());
 
-    BACKEND_CONFIG.with(|tls_backend_config| {
-        assert!(tls_backend_config.borrow_mut().replace(backend_config).is_none())
+    let start_sig = Signature {
+        params: vec![
+            AbiParam::new(jit_module.target_config().pointer_type()),
+            AbiParam::new(jit_module.target_config().pointer_type()),
+        ],
+        returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)],
+        call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
+    };
+    let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap();
+    let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
+
+    LAZY_JIT_STATE.with(|lazy_jit_state| {
+        let mut lazy_jit_state = lazy_jit_state.borrow_mut();
+        assert!(lazy_jit_state.is_none());
+        *lazy_jit_state = Some(JitState { backend_config, jit_module });
     });
 
-    let (main_def_id, entry_ty) = tcx.entry_fn(LOCAL_CRATE).unwrap();
-    let instance = Instance::mono(tcx, main_def_id.to_def_id()).polymorphize(tcx);
-
-    match entry_ty {
-        EntryFnType::Main => {
-            // FIXME set program arguments somehow
-
-            let main_sig = Signature {
-                params: vec![],
-                returns: vec![],
-                call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
-            };
-            let main_func_id = jit_module
-                .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &main_sig)
-                .unwrap();
-            let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
-
-            CURRENT_MODULE.with(|current_module| {
-                assert!(current_module.borrow_mut().replace(jit_module).is_none())
-            });
-
-            let f: extern "C" fn() = unsafe { ::std::mem::transmute(finalized_main) };
-            f();
-            std::process::exit(0);
-        }
-        EntryFnType::Start => {
-            let start_sig = Signature {
-                params: vec![
-                    AbiParam::new(jit_module.target_config().pointer_type()),
-                    AbiParam::new(jit_module.target_config().pointer_type()),
-                ],
-                returns: vec![AbiParam::new(
-                    jit_module.target_config().pointer_type(), /*isize*/
-                )],
-                call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
-            };
-            let start_func_id = jit_module
-                .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &start_sig)
-                .unwrap();
-            let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
-
-            CURRENT_MODULE.with(|current_module| {
-                assert!(current_module.borrow_mut().replace(jit_module).is_none())
-            });
-
-            let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
-                unsafe { ::std::mem::transmute(finalized_start) };
-            let ret = f(args.len() as c_int, argv.as_ptr());
-            std::process::exit(ret);
-        }
-    }
+    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
+        unsafe { ::std::mem::transmute(finalized_start) };
+    let ret = f(args.len() as c_int, argv.as_ptr());
+    std::process::exit(ret);
 }
 
 #[no_mangle]
@@ -161,24 +151,23 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8
         // lift is used to ensure the correct lifetime for instance.
         let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
 
-        CURRENT_MODULE.with(|jit_module| {
-            let mut jit_module = jit_module.borrow_mut();
-            let jit_module = jit_module.as_mut().unwrap();
-            let backend_config =
-                BACKEND_CONFIG.with(|backend_config| backend_config.borrow().clone().unwrap());
+        LAZY_JIT_STATE.with(|lazy_jit_state| {
+            let mut lazy_jit_state = lazy_jit_state.borrow_mut();
+            let lazy_jit_state = lazy_jit_state.as_mut().unwrap();
+            let jit_module = &mut lazy_jit_state.jit_module;
+            let backend_config = lazy_jit_state.backend_config.clone();
 
-            let name = tcx.symbol_name(instance).name.to_string();
+            let name = tcx.symbol_name(instance).name;
             let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
-            let func_id = jit_module.declare_function(&name, Linkage::Export, &sig).unwrap();
+            let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
             jit_module.prepare_for_function_redefine(func_id).unwrap();
 
-            let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module, false);
-            tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, instance));
+            let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false);
+            tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance));
 
-            let (global_asm, _debug_context, unwind_context) = cx.finalize();
-            assert!(global_asm.is_empty());
+            assert!(cx.global_asm.is_empty());
             jit_module.finalize_definitions();
-            std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) });
+            unsafe { cx.unwind_context.register_jit(&jit_module) };
             jit_module.get_finalized_function(func_id)
         })
     })
@@ -248,35 +237,37 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
     imported_symbols
 }
 
-fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) {
+fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) {
     let tcx = cx.tcx;
 
-    let pointer_type = cx.module.target_config().pointer_type();
+    let pointer_type = module.target_config().pointer_type();
 
-    let name = tcx.symbol_name(inst).name.to_string();
-    let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), inst);
-    let func_id = cx.module.declare_function(&name, Linkage::Export, &sig).unwrap();
+    let name = tcx.symbol_name(inst).name;
+    let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
+    let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
 
     let instance_ptr = Box::into_raw(Box::new(inst));
 
-    let jit_fn = cx
-        .module
+    let jit_fn = module
         .declare_function(
             "__clif_jit_fn",
             Linkage::Import,
             &Signature {
-                call_conv: cx.module.target_config().default_call_conv,
+                call_conv: module.target_config().default_call_conv,
                 params: vec![AbiParam::new(pointer_type)],
                 returns: vec![AbiParam::new(pointer_type)],
             },
         )
         .unwrap();
 
-    let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone());
+    cx.cached_context.clear();
+    let trampoline = &mut cx.cached_context.func;
+    trampoline.signature = sig.clone();
+
     let mut builder_ctx = FunctionBuilderContext::new();
-    let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx);
+    let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx);
 
-    let jit_fn = cx.module.declare_func_in_func(jit_fn, trampoline_builder.func);
+    let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func);
     let sig_ref = trampoline_builder.func.import_signature(sig);
 
     let entry_block = trampoline_builder.create_block();
@@ -291,10 +282,10 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) {
     let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
     trampoline_builder.ins().return_(&ret_vals);
 
-    cx.module
+    module
         .define_function(
             func_id,
-            &mut Context::for_function(trampoline),
+            &mut cx.cached_context,
             &mut NullTrapSink {},
             &mut NullStackMapSink {},
         )
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index d49182a07b7..8f5714ecb41 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -1,63 +1,37 @@
-//! Drivers are responsible for calling [`codegen_mono_item`] and performing any further actions
-//! like JIT executing or writing object files.
+//! Drivers are responsible for calling [`codegen_fn`] or [`codegen_static`] for each mono item and
+//! performing any further actions like JIT executing or writing object files.
+//!
+//! [`codegen_fn`]: crate::base::codegen_fn
+//! [`codegen_static`]: crate::constant::codegen_static
 
-use std::any::Any;
-
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
 
 use crate::prelude::*;
-use crate::CodegenMode;
 
-mod aot;
+pub(crate) mod aot;
 #[cfg(feature = "jit")]
-mod jit;
-
-pub(crate) fn codegen_crate(
-    tcx: TyCtxt<'_>,
-    metadata: EncodedMetadata,
-    need_metadata_module: bool,
-    backend_config: crate::BackendConfig,
-) -> Box<dyn Any> {
-    tcx.sess.abort_if_errors();
-
-    match backend_config.codegen_mode {
-        CodegenMode::Aot => aot::run_aot(tcx, backend_config, metadata, need_metadata_module),
-        CodegenMode::Jit | CodegenMode::JitLazy => {
-            let is_executable =
-                tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable);
-            if !is_executable {
-                tcx.sess.fatal("can't jit non-executable crate");
-            }
-
-            #[cfg(feature = "jit")]
-            let _: ! = jit::run_jit(tcx, backend_config);
-
-            #[cfg(not(feature = "jit"))]
-            tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
-        }
-    }
-}
+pub(crate) mod jit;
 
 fn predefine_mono_items<'tcx>(
-    cx: &mut crate::CodegenCx<'_, 'tcx>,
+    tcx: TyCtxt<'tcx>,
+    module: &mut dyn Module,
     mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))],
 ) {
-    cx.tcx.sess.time("predefine functions", || {
-        let is_compiler_builtins = cx.tcx.is_compiler_builtins(LOCAL_CRATE);
+    tcx.sess.time("predefine functions", || {
+        let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE);
         for &(mono_item, (linkage, visibility)) in mono_items {
             match mono_item {
                 MonoItem::Fn(instance) => {
-                    let name = cx.tcx.symbol_name(instance).name.to_string();
+                    let name = tcx.symbol_name(instance).name;
                     let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
-                    let sig = get_function_sig(cx.tcx, cx.module.isa().triple(), instance);
+                    let sig = get_function_sig(tcx, module.isa().triple(), instance);
                     let linkage = crate::linkage::get_clif_linkage(
                         mono_item,
                         linkage,
                         visibility,
                         is_compiler_builtins,
                     );
-                    cx.module.declare_function(&name, linkage, &sig).unwrap();
+                    module.declare_function(name, linkage, &sig).unwrap();
                 }
                 MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
             }
@@ -65,8 +39,8 @@ fn predefine_mono_items<'tcx>(
     });
 }
 
-fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
-    if std::env::var("CG_CLIF_DISPLAY_CG_TIME").as_ref().map(|val| &**val) == Ok("1") {
+fn time<R>(tcx: TyCtxt<'_>, display: bool, name: &'static str, f: impl FnOnce() -> R) -> R {
+    if display {
         println!("[{:<30}: {}] start", tcx.crate_name(LOCAL_CRATE), name);
         let before = std::time::Instant::now();
         let res = tcx.sess.time(name, f);
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 1fb5e86aed7..4ab4c2957ca 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -24,6 +24,64 @@ pub(crate) fn codegen_inline_asm<'tcx>(
         let true_ = fx.bcx.ins().iconst(types::I32, 1);
         fx.bcx.ins().trapnz(true_, TrapCode::User(1));
         return;
+    } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string())
+        && template[1] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string())
+        && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string())
+    {
+        assert_eq!(operands.len(), 4);
+        let (leaf, eax_place) = match operands[0] {
+            InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
+                (
+                    crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+                    crate::base::codegen_place(fx, out_place.unwrap()),
+                )
+            }
+            _ => unreachable!(),
+        };
+        let ebx_place = match operands[1] {
+            InlineAsmOperand::Out { reg, late: true, place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si));
+                crate::base::codegen_place(fx, place.unwrap())
+            }
+            _ => unreachable!(),
+        };
+        let (sub_leaf, ecx_place) = match operands[2] {
+            InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::cx));
+                (
+                    crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+                    crate::base::codegen_place(fx, out_place.unwrap()),
+                )
+            }
+            _ => unreachable!(),
+        };
+        let edx_place = match operands[3] {
+            InlineAsmOperand::Out { reg, late: true, place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::dx));
+                crate::base::codegen_place(fx, place.unwrap())
+            }
+            _ => unreachable!(),
+        };
+
+        let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
+
+        eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
+        ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
+        ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
+        edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
+        return;
+    } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
+        // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
+        crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
+    } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
+        crate::trap::trap_unimplemented(fx, "Alloca is not supported");
     }
 
     let mut slot_size = Size::from_bytes(0);
@@ -92,8 +150,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
 
     let inline_asm_index = fx.inline_asm_index;
     fx.inline_asm_index += 1;
-    let asm_name =
-        format!("{}__inline_asm_{}", fx.tcx.symbol_name(fx.instance).name, inline_asm_index);
+    let asm_name = format!("{}__inline_asm_{}", fx.symbol_name, inline_asm_index);
 
     let generated_asm = generate_asm_wrapper(
         &asm_name,
@@ -202,7 +259,6 @@ fn call_inline_asm<'tcx>(
     }
 
     let inline_asm_func = fx
-        .cx
         .module
         .declare_function(
             asm_name,
@@ -214,7 +270,7 @@ fn call_inline_asm<'tcx>(
             },
         )
         .unwrap();
-    let inline_asm_func = fx.cx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func);
+    let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(inline_asm_func, asm_name);
     }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
index b27b0eddfba..9de12e759bc 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
@@ -8,7 +8,7 @@ use crate::prelude::*;
 pub(crate) fn codegen_cpuid_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     leaf: Value,
-    _subleaf: Value,
+    _sub_leaf: Value,
 ) -> (Value, Value, Value, Value) {
     let leaf_0 = fx.bcx.create_block();
     let leaf_1 = fx.bcx.create_block();
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index 83c91f789cd..ba4ed2162cd 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -22,7 +22,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
         };
 
         // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
-        llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) {
+        "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) {
             let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
             let lane_ty = fx.clif_type(lane_ty).unwrap();
             assert!(lane_count <= 32);
@@ -51,7 +51,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
             let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
             ret.write_cvalue(fx, res);
         };
-        llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) {
+        "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) {
             let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const");
             let flt_cc = match kind_const.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) {
                 0 => FloatCC::Equal,
@@ -81,7 +81,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                 bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane)
             });
         };
-        llvm.x86.sse2.psrli.d, (c a, o imm8) {
+        "llvm.x86.sse2.psrli.d", (c a, o imm8) {
             let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
             simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
                 let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
@@ -91,7 +91,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                 CValue::by_val(res_lane, res_lane_layout)
             });
         };
-        llvm.x86.sse2.pslli.d, (c a, o imm8) {
+        "llvm.x86.sse2.pslli.d", (c a, o imm8) {
             let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
             simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
                 let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
@@ -101,7 +101,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                 CValue::by_val(res_lane, res_lane_layout)
             });
         };
-        llvm.x86.sse2.storeu.dq, (v mem_addr, c a) {
+        "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) {
             // FIXME correctly handle the unalignment
             let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
             dest.write_cvalue(fx, a);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 39e047a98f9..435737f3a51 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -8,23 +8,25 @@ mod simd;
 pub(crate) use cpuid::codegen_cpuid_call;
 pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
+use rustc_span::symbol::{sym, kw};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+
 use crate::prelude::*;
 use cranelift_codegen::ir::AtomicRmwOp;
-use rustc_middle::ty::print::with_no_trimmed_paths;
 
 macro intrinsic_pat {
     (_) => {
         _
     },
     ($name:ident) => {
-        stringify!($name)
+        sym::$name
+    },
+    (kw.$name:ident) => {
+        kw::$name
     },
     ($name:literal) => {
-        stringify!($name)
+        $name
     },
-    ($x:ident . $($xs:tt).*) => {
-        concat!(stringify!($x), ".", intrinsic_pat!($($xs).*))
-    }
 }
 
 macro intrinsic_arg {
@@ -87,7 +89,7 @@ macro call_intrinsic_match {
     )*) => {
         match $intrinsic {
             $(
-                stringify!($name) => {
+                sym::$name => {
                     assert!($substs.is_noop());
                     if let [$(ref $arg),*] = *$args {
                         let ($($arg,)*) = (
@@ -400,18 +402,17 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
     let def_id = instance.def_id();
     let substs = instance.substs;
 
-    let intrinsic = fx.tcx.item_name(def_id).as_str();
-    let intrinsic = &intrinsic[..];
+    let intrinsic = fx.tcx.item_name(def_id);
 
     let ret = match destination {
         Some((place, _)) => place,
         None => {
             // Insert non returning intrinsics here
             match intrinsic {
-                "abort" => {
+                sym::abort => {
                     trap_abort(fx, "Called intrinsic::abort.");
                 }
-                "transmute" => {
+                sym::transmute => {
                     crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
                 }
                 _ => unimplemented!("unsupported instrinsic {}", intrinsic),
@@ -420,7 +421,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         }
     };
 
-    if intrinsic.starts_with("simd_") {
+    if intrinsic.as_str().starts_with("simd_") {
         self::simd::codegen_simd_intrinsic_call(fx, instance, args, ret, span);
         let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1);
         fx.bcx.ins().jump(ret_block, &[]);
@@ -470,8 +471,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         sinf64(flt) -> f64 => sin,
         cosf32(flt) -> f32 => cosf,
         cosf64(flt) -> f64 => cos,
-        tanf32(flt) -> f32 => tanf,
-        tanf64(flt) -> f64 => tan,
     }
 
     intrinsic_match! {
@@ -496,12 +495,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 count
             };
 
-            if intrinsic.contains("nonoverlapping") {
+            if intrinsic == sym::copy_nonoverlapping {
                 // FIXME emit_small_memcpy
-                fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount);
             } else {
                 // FIXME emit_small_memmove
-                fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount);
             }
         };
         // NOTE: the volatile variants have src and dst swapped
@@ -515,12 +514,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             };
 
             // FIXME make the copy actually volatile when using emit_small_mem{cpy,move}
-            if intrinsic.contains("nonoverlapping") {
+            if intrinsic == sym::volatile_copy_nonoverlapping_memory {
                 // FIXME emit_small_memcpy
-                fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount);
             } else {
                 // FIXME emit_small_memmove
-                fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount);
             }
         };
         size_of_val, <T> (c ptr) {
@@ -552,27 +551,28 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
         };
 
-        _ if intrinsic.starts_with("unchecked_") || intrinsic == "exact_div", (c x, c y) {
+        unchecked_add | unchecked_sub | unchecked_div | exact_div | unchecked_rem
+        | unchecked_shl | unchecked_shr, (c x, c y) {
             // FIXME trap on overflow
             let bin_op = match intrinsic {
-                "unchecked_add" => BinOp::Add,
-                "unchecked_sub" => BinOp::Sub,
-                "unchecked_div" | "exact_div" => BinOp::Div,
-                "unchecked_rem" => BinOp::Rem,
-                "unchecked_shl" => BinOp::Shl,
-                "unchecked_shr" => BinOp::Shr,
-                _ => unreachable!("intrinsic {}", intrinsic),
+                sym::unchecked_add => BinOp::Add,
+                sym::unchecked_sub => BinOp::Sub,
+                sym::unchecked_div | sym::exact_div => BinOp::Div,
+                sym::unchecked_rem => BinOp::Rem,
+                sym::unchecked_shl => BinOp::Shl,
+                sym::unchecked_shr => BinOp::Shr,
+                _ => unreachable!(),
             };
             let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
             ret.write_cvalue(fx, res);
         };
-        _ if intrinsic.ends_with("_with_overflow"), (c x, c y) {
+        add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) {
             assert_eq!(x.layout().ty, y.layout().ty);
             let bin_op = match intrinsic {
-                "add_with_overflow" => BinOp::Add,
-                "sub_with_overflow" => BinOp::Sub,
-                "mul_with_overflow" => BinOp::Mul,
-                _ => unreachable!("intrinsic {}", intrinsic),
+                sym::add_with_overflow => BinOp::Add,
+                sym::sub_with_overflow => BinOp::Sub,
+                sym::mul_with_overflow => BinOp::Mul,
+                _ => unreachable!(),
             };
 
             let res = crate::num::codegen_checked_int_binop(
@@ -583,12 +583,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             );
             ret.write_cvalue(fx, res);
         };
-        _ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) {
+        saturating_add | saturating_sub, <T> (c lhs, c rhs) {
             assert_eq!(lhs.layout().ty, rhs.layout().ty);
             let bin_op = match intrinsic {
-                "saturating_add" => BinOp::Add,
-                "saturating_sub" => BinOp::Sub,
-                _ => unreachable!("intrinsic {}", intrinsic),
+                sym::saturating_add => BinOp::Add,
+                sym::saturating_sub => BinOp::Sub,
+                _ => unreachable!(),
             };
 
             let signed = type_sign(T);
@@ -609,15 +609,15 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
 
             let val = match (intrinsic, signed) {
-                ("saturating_add", false) => fx.bcx.ins().select(has_overflow, max, val),
-                ("saturating_sub", false) => fx.bcx.ins().select(has_overflow, min, val),
-                ("saturating_add", true) => {
+                (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val),
+                (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
+                (sym::saturating_add, true) => {
                     let rhs = rhs.load_scalar(fx);
                     let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
                     fx.bcx.ins().select(has_overflow, sat_val, val)
                 }
-                ("saturating_sub", true) => {
+                (sym::saturating_sub, true) => {
                     let rhs = rhs.load_scalar(fx);
                     let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
@@ -632,11 +632,21 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         };
         rotate_left, <T>(v x, v y) {
             let layout = fx.layout_of(T);
+            let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
+                fx.bcx.ins().ireduce(types::I64, y)
+            } else {
+                y
+            };
             let res = fx.bcx.ins().rotl(x, y);
             ret.write_cvalue(fx, CValue::by_val(res, layout));
         };
         rotate_right, <T>(v x, v y) {
             let layout = fx.layout_of(T);
+            let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
+                fx.bcx.ins().ireduce(types::I64, y)
+            } else {
+                y
+            };
             let res = fx.bcx.ins().rotr(x, y);
             ret.write_cvalue(fx, CValue::by_val(res, layout));
         };
@@ -670,7 +680,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let dst_ptr = dst.load_scalar(fx);
             // FIXME make the memset actually volatile when switching to emit_small_memset
             // FIXME use emit_small_memset
-            fx.bcx.call_memset(fx.cx.module.target_config(), dst_ptr, val, count);
+            fx.bcx.call_memset(fx.module.target_config(), dst_ptr, val, count);
         };
         ctlz | ctlz_nonzero, <T> (v arg) {
             // FIXME trap on `ctlz_nonzero` with zero arg.
@@ -806,7 +816,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 return;
             }
 
-            if intrinsic == "assert_zero_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() {
+            if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() {
                 with_no_trimmed_paths(|| crate::base::codegen_panic(
                     fx,
                     &format!("attempted to zero-initialize type `{}`, which is invalid", T),
@@ -815,7 +825,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 return;
             }
 
-            if intrinsic == "assert_uninit_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() {
+            if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() {
                 with_no_trimmed_paths(|| crate::base::codegen_panic(
                     fx,
                     &format!("attempted to leave type `{}` uninitialized, which is invalid", T),
@@ -827,7 +837,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
 
         volatile_load | unaligned_volatile_load, (c ptr) {
             // Cranelift treats loads as volatile by default
-            // FIXME ignore during stack2reg optimization
             // FIXME correctly handle unaligned_volatile_load
             let inner_layout =
                 fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
@@ -836,7 +845,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         };
         volatile_store | unaligned_volatile_store, (v ptr, c val) {
             // Cranelift treats stores as volatile by default
-            // FIXME ignore during stack2reg optimization
             // FIXME correctly handle unaligned_volatile_store
             let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
             dest.write_cvalue(fx, val);
@@ -878,14 +886,14 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, caller_location);
         };
 
-        _ if intrinsic.starts_with("atomic_fence"), () {
+        _ if intrinsic.as_str().starts_with("atomic_fence"), () {
             fx.bcx.ins().fence();
         };
-        _ if intrinsic.starts_with("atomic_singlethreadfence"), () {
+        _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () {
             // FIXME use a compiler fence once Cranelift supports it
             fx.bcx.ins().fence();
         };
-        _ if intrinsic.starts_with("atomic_load"), <T> (v ptr) {
+        _ if intrinsic.as_str().starts_with("atomic_load"), <T> (v ptr) {
             validate_atomic_type!(fx, intrinsic, span, T);
             let ty = fx.clif_type(T).unwrap();
 
@@ -894,14 +902,14 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let val = CValue::by_val(val, fx.layout_of(T));
             ret.write_cvalue(fx, val);
         };
-        _ if intrinsic.starts_with("atomic_store"), (v ptr, c val) {
+        _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) {
             validate_atomic_type!(fx, intrinsic, span, val.layout().ty);
 
             let val = val.load_scalar(fx);
 
             fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr);
         };
-        _ if intrinsic.starts_with("atomic_xchg"), (v ptr, c new) {
+        _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) {
             let layout = new.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -913,7 +921,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
+        _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
             let layout = new.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
 
@@ -927,7 +935,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, ret_val)
         };
 
-        _ if intrinsic.starts_with("atomic_xadd"), (v ptr, c amount) {
+        _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) {
             let layout = amount.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -939,7 +947,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_xsub"), (v ptr, c amount) {
+        _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) {
             let layout = amount.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -951,7 +959,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_and"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -963,7 +971,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_or"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -975,7 +983,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_xor"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -989,7 +997,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         };
 
         // FIXME https://github.com/bytecodealliance/wasmtime/issues/2647
-        _ if intrinsic.starts_with("atomic_nand"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1001,7 +1009,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_max"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1013,7 +1021,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_umax"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1025,7 +1033,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_min"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1037,7 +1045,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_umin"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1071,7 +1079,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, val);
         };
 
-        try, (v f, v data, v _catch_fn) {
+        kw.Try, (v f, v data, v _catch_fn) {
             // FIXME once unwinding is supported, change this to actually catch panics
             let f_sig = fx.bcx.func.import_signature(Signature {
                 call_conv: CallConv::triple_default(fx.triple()),
@@ -1088,11 +1096,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
 
         fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) {
             let res = crate::num::codegen_float_binop(fx, match intrinsic {
-                "fadd_fast" => BinOp::Add,
-                "fsub_fast" => BinOp::Sub,
-                "fmul_fast" => BinOp::Mul,
-                "fdiv_fast" => BinOp::Div,
-                "frem_fast" => BinOp::Rem,
+                sym::fadd_fast => BinOp::Add,
+                sym::fsub_fast => BinOp::Sub,
+                sym::fmul_fast => BinOp::Mul,
+                sym::fdiv_fast => BinOp::Div,
+                sym::frem_fast => BinOp::Rem,
                 _ => unreachable!(),
             }, x, y);
             ret.write_cvalue(fx, res);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 27fc2abedc7..940d2514f74 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -13,8 +13,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
     let def_id = instance.def_id();
     let substs = instance.substs;
 
-    let intrinsic = fx.tcx.item_name(def_id).as_str();
-    let intrinsic = &intrinsic[..];
+    let intrinsic = fx.tcx.item_name(def_id);
 
     intrinsic_match! {
         fx, intrinsic, substs, args,
@@ -65,10 +64,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
         };
 
         // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
-        _ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
+        _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) {
             validate_simd_type!(fx, intrinsic, span, x.layout().ty);
 
-            let n: u16 = intrinsic["simd_shuffle".len()..].parse().unwrap();
+            let n: u16 = intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap();
 
             assert_eq!(x.layout(), y.layout());
             let layout = x.layout();
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 720d2a12534..32f40395702 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_private, decl_macro, never_type, hash_drain_filter)]
+#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)]
 #![warn(rust_2018_idioms)]
 #![warn(unused_lifetimes)]
 #![warn(unreachable_pub)]
@@ -23,7 +23,6 @@ extern crate rustc_target;
 extern crate rustc_driver;
 
 use std::any::Any;
-use std::str::FromStr;
 
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
@@ -34,9 +33,10 @@ use rustc_middle::ty::query::Providers;
 use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
 
+use cranelift_codegen::isa::TargetIsa;
 use cranelift_codegen::settings::{self, Configurable};
 
-use crate::constant::ConstantCx;
+pub use crate::config::*;
 use crate::prelude::*;
 
 mod abi;
@@ -49,6 +49,7 @@ mod cast;
 mod codegen_i128;
 mod common;
 mod compiler_builtins;
+mod config;
 mod constant;
 mod debuginfo;
 mod discriminant;
@@ -87,7 +88,6 @@ mod prelude {
 
     pub(crate) use rustc_index::vec::Idx;
 
-    pub(crate) use cranelift_codegen::entity::EntitySet;
     pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
     pub(crate) use cranelift_codegen::ir::function::Function;
     pub(crate) use cranelift_codegen::ir::types;
@@ -119,95 +119,36 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
     }
 }
 
-struct CodegenCx<'m, 'tcx: 'm> {
+/// The codegen context holds any information shared between the codegen of individual functions
+/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
+struct CodegenCx<'tcx> {
     tcx: TyCtxt<'tcx>,
-    module: &'m mut dyn Module,
     global_asm: String,
-    constants_cx: ConstantCx,
     cached_context: Context,
-    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
     debug_context: Option<DebugContext<'tcx>>,
-    unwind_context: UnwindContext<'tcx>,
+    unwind_context: UnwindContext,
 }
 
-impl<'m, 'tcx> CodegenCx<'m, 'tcx> {
+impl<'tcx> CodegenCx<'tcx> {
     fn new(
         tcx: TyCtxt<'tcx>,
         backend_config: BackendConfig,
-        module: &'m mut dyn Module,
+        isa: &dyn TargetIsa,
         debug_info: bool,
     ) -> Self {
-        let unwind_context = UnwindContext::new(
-            tcx,
-            module.isa(),
-            matches!(backend_config.codegen_mode, CodegenMode::Aot),
-        );
-        let debug_context =
-            if debug_info { Some(DebugContext::new(tcx, module.isa())) } else { None };
+        assert_eq!(pointer_ty(tcx), isa.pointer_type());
+
+        let unwind_context =
+            UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
+        let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
         CodegenCx {
             tcx,
-            module,
             global_asm: String::new(),
-            constants_cx: ConstantCx::default(),
             cached_context: Context::new(),
-            vtables: FxHashMap::default(),
             debug_context,
             unwind_context,
         }
     }
-
-    fn finalize(self) -> (String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
-        self.constants_cx.finalize(self.tcx, self.module);
-        (self.global_asm, self.debug_context, self.unwind_context)
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum CodegenMode {
-    Aot,
-    Jit,
-    JitLazy,
-}
-
-impl Default for CodegenMode {
-    fn default() -> Self {
-        CodegenMode::Aot
-    }
-}
-
-impl FromStr for CodegenMode {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "aot" => Ok(CodegenMode::Aot),
-            "jit" => Ok(CodegenMode::Jit),
-            "jit-lazy" => Ok(CodegenMode::JitLazy),
-            _ => Err(format!("Unknown codegen mode `{}`", s)),
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, Default)]
-pub struct BackendConfig {
-    pub codegen_mode: CodegenMode,
-}
-
-impl BackendConfig {
-    fn from_opts(opts: &[String]) -> Result<Self, String> {
-        let mut config = BackendConfig::default();
-        for opt in opts {
-            if let Some((name, value)) = opt.split_once('=') {
-                match name {
-                    "mode" => config.codegen_mode = value.parse()?,
-                    _ => return Err(format!("Unknown option `{}`", name)),
-                }
-            } else {
-                return Err(format!("Invalid option `{}`", opt));
-            }
-        }
-        Ok(config)
-    }
 }
 
 pub struct CraneliftCodegenBackend {
@@ -240,13 +181,23 @@ impl CodegenBackend for CraneliftCodegenBackend {
         metadata: EncodedMetadata,
         need_metadata_module: bool,
     ) -> Box<dyn Any> {
-        let config = if let Some(config) = self.config {
+        tcx.sess.abort_if_errors();
+        let config = if let Some(config) = self.config.clone() {
             config
         } else {
             BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
                 .unwrap_or_else(|err| tcx.sess.fatal(&err))
         };
-        driver::codegen_crate(tcx, metadata, need_metadata_module, config)
+        match config.codegen_mode {
+            CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
+            CodegenMode::Jit | CodegenMode::JitLazy => {
+                #[cfg(feature = "jit")]
+                let _: ! = driver::jit::run_jit(tcx, config);
+
+                #[cfg(not(feature = "jit"))]
+                tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+            }
+        }
     }
 
     fn join_codegen(
@@ -284,7 +235,7 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
     sess.target.llvm_target.parse().unwrap()
 }
 
-fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
+fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
     use target_lexicon::BinaryFormat;
 
     let target_triple = crate::target_triple(sess);
@@ -292,9 +243,8 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
     let mut flags_builder = settings::builder();
     flags_builder.enable("is_pic").unwrap();
     flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
-    let enable_verifier =
-        cfg!(debug_assertions) || std::env::var("CG_CLIF_ENABLE_VERIFIER").is_ok();
-    flags_builder.set("enable_verifier", if enable_verifier { "true" } else { "false" }).unwrap();
+    let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
+    flags_builder.set("enable_verifier", enable_verifier).unwrap();
 
     let tls_model = match target_triple.binary_format {
         BinaryFormat::Elf => "elf_gd",
@@ -322,10 +272,28 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
     let flags = settings::Flags::new(flags_builder);
 
     let variant = cranelift_codegen::isa::BackendVariant::MachInst;
-    let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
-    // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
-    // is interpreted as `bsr`.
-    isa_builder.enable("nehalem").unwrap();
+
+    let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
+        Some("native") => {
+            let builder = cranelift_native::builder_with_options(variant, true).unwrap();
+            builder
+        }
+        Some(value) => {
+            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            if let Err(_) = builder.enable(value) {
+                sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
+            }
+            builder
+        }
+        None => {
+            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            // Don't use "haswell" as the default, as it implies `has_lzcnt`.
+            // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
+            builder.enable("nehalem").unwrap();
+            builder
+        }
+    };
+    
     isa_builder.finish(flags)
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/linkage.rs b/compiler/rustc_codegen_cranelift/src/linkage.rs
index a564a59f725..ca853aac158 100644
--- a/compiler/rustc_codegen_cranelift/src/linkage.rs
+++ b/compiler/rustc_codegen_cranelift/src/linkage.rs
@@ -13,6 +13,7 @@ pub(crate) fn get_clif_linkage(
         (RLinkage::External, Visibility::Default) => Linkage::Export,
         (RLinkage::Internal, Visibility::Default) => Linkage::Local,
         (RLinkage::External, Visibility::Hidden) => Linkage::Hidden,
+        (RLinkage::WeakAny, Visibility::Default) => Linkage::Preemptible,
         _ => panic!("{:?} = {:?} {:?}", mono_item, linkage, visibility),
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index a6266f50776..d504024a335 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -1,6 +1,9 @@
 use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
 use rustc_hir::LangItem;
+use rustc_middle::ty::subst::GenericArg;
+use rustc_middle::ty::AssocKind;
 use rustc_session::config::EntryFnType;
+use rustc_span::symbol::Ident;
 
 use crate::prelude::*;
 
@@ -9,11 +12,12 @@ use crate::prelude::*;
 pub(crate) fn maybe_create_entry_wrapper(
     tcx: TyCtxt<'_>,
     module: &mut impl Module,
-    unwind_context: &mut UnwindContext<'_>,
+    unwind_context: &mut UnwindContext,
+    is_jit: bool,
 ) {
-    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
+    let (main_def_id, is_main_fn) = match tcx.entry_fn(LOCAL_CRATE) {
         Some((def_id, entry_ty)) => (
-            def_id.to_def_id(),
+            def_id,
             match entry_ty {
                 EntryFnType::Main => true,
                 EntryFnType::Start => false,
@@ -23,18 +27,19 @@ pub(crate) fn maybe_create_entry_wrapper(
     };
 
     let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
-    if module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+    if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
         return;
     }
 
-    create_entry_fn(tcx, module, unwind_context, main_def_id, use_start_lang_item);
+    create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn);
 
     fn create_entry_fn(
         tcx: TyCtxt<'_>,
         m: &mut impl Module,
-        unwind_context: &mut UnwindContext<'_>,
+        unwind_context: &mut UnwindContext,
         rust_main_def_id: DefId,
-        use_start_lang_item: bool,
+        ignore_lang_start_wrapper: bool,
+        is_main_fn: bool,
     ) {
         let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
         // Given that `main()` has no arguments,
@@ -57,9 +62,9 @@ pub(crate) fn maybe_create_entry_wrapper(
 
         let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
 
-        let main_name = tcx.symbol_name(instance).name.to_string();
+        let main_name = tcx.symbol_name(instance).name;
         let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
-        let main_func_id = m.declare_function(&main_name, Linkage::Import, &main_sig).unwrap();
+        let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
 
         let mut ctx = Context::new();
         ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig);
@@ -74,7 +79,47 @@ pub(crate) fn maybe_create_entry_wrapper(
 
             let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
 
-            let call_inst = if use_start_lang_item {
+            let result = if is_main_fn && ignore_lang_start_wrapper {
+                // regular main fn, but ignoring #[lang = "start"] as we are running in the jit
+                // FIXME set program arguments somehow
+                let call_inst = bcx.ins().call(main_func_ref, &[]);
+                let call_results = bcx.func.dfg.inst_results(call_inst).to_owned();
+
+                let termination_trait = tcx.require_lang_item(LangItem::Termination, None);
+                let report = tcx
+                    .associated_items(termination_trait)
+                    .find_by_name_and_kind(
+                        tcx,
+                        Ident::from_str("report"),
+                        AssocKind::Fn,
+                        termination_trait,
+                    )
+                    .unwrap();
+                let report = Instance::resolve(
+                    tcx,
+                    ParamEnv::reveal_all(),
+                    report.def_id,
+                    tcx.mk_substs([GenericArg::from(main_ret_ty)].iter()),
+                )
+                .unwrap()
+                .unwrap();
+
+                let report_name = tcx.symbol_name(report).name;
+                let report_sig = get_function_sig(tcx, m.isa().triple(), report);
+                let report_func_id =
+                    m.declare_function(report_name, Linkage::Import, &report_sig).unwrap();
+                let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func);
+
+                // FIXME do proper abi handling instead of expecting the pass mode to be identical
+                // for returns and arguments.
+                let report_call_inst = bcx.ins().call(report_func_ref, &call_results);
+                let res = bcx.func.dfg.inst_results(report_call_inst)[0];
+                match m.target_config().pointer_type() {
+                    types::I32 => res,
+                    types::I64 => bcx.ins().sextend(types::I64, res),
+                    _ => unimplemented!("16bit systems are not yet supported"),
+                }
+            } else if is_main_fn {
                 let start_def_id = tcx.require_lang_item(LangItem::Start, None);
                 let start_instance = Instance::resolve(
                     tcx,
@@ -90,13 +135,14 @@ pub(crate) fn maybe_create_entry_wrapper(
                 let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
 
                 let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
-                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
+                let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]);
+                bcx.inst_results(call_inst)[0]
             } else {
                 // using user-defined start fn
-                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
+                let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]);
+                bcx.inst_results(call_inst)[0]
             };
 
-            let result = bcx.inst_results(call_inst)[0];
             bcx.ins().return_(&[result]);
             bcx.seal_all_blocks();
             bcx.finalize();
diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs
index dbdc8cbad44..882232fde09 100644
--- a/compiler/rustc_codegen_cranelift/src/metadata.rs
+++ b/compiler/rustc_codegen_cranelift/src/metadata.rs
@@ -8,13 +8,24 @@ use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::rustc_erase_owner;
 use rustc_data_structures::sync::MetadataRef;
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
+use rustc_middle::middle::cstore::MetadataLoader;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config;
 use rustc_target::spec::Target;
 
 use crate::backend::WriteMetadata;
 
+/// The metadata loader used by cg_clif.
+///
+/// The metadata is stored in the same format as cg_llvm.
+///
+/// # Metadata location
+///
+/// <dl>
+/// <dt>rlib</dt>
+/// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd>
+/// <dt>dylib</dt>
+/// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd>
+/// </dl>
 pub(crate) struct CraneliftMetadataLoader;
 
 fn load_metadata_with(
@@ -58,54 +69,16 @@ impl MetadataLoader for CraneliftMetadataLoader {
 }
 
 // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
-pub(crate) fn write_metadata<P: WriteMetadata>(
-    tcx: TyCtxt<'_>,
-    product: &mut P,
-) -> EncodedMetadata {
+pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
     use snap::write::FrameEncoder;
     use std::io::Write;
 
-    #[derive(PartialEq, Eq, PartialOrd, Ord)]
-    enum MetadataKind {
-        None,
-        Uncompressed,
-        Compressed,
-    }
-
-    let kind = tcx
-        .sess
-        .crate_types()
-        .iter()
-        .map(|ty| match *ty {
-            config::CrateType::Executable
-            | config::CrateType::Staticlib
-            | config::CrateType::Cdylib => MetadataKind::None,
-
-            config::CrateType::Rlib => MetadataKind::Uncompressed,
-
-            config::CrateType::Dylib | config::CrateType::ProcMacro => MetadataKind::Compressed,
-        })
-        .max()
-        .unwrap_or(MetadataKind::None);
-
-    if kind == MetadataKind::None {
-        return EncodedMetadata::new();
-    }
-
     let metadata = tcx.encode_metadata();
-    if kind == MetadataKind::Uncompressed {
-        return metadata;
-    }
-
-    assert!(kind == MetadataKind::Compressed);
     let mut compressed = tcx.metadata_encoding_version();
     FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
 
-    product.add_rustc_section(
+    object.add_rustc_section(
         rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx),
         compressed,
-        tcx.sess.target.is_like_osx,
     );
-
-    metadata
 }
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 2ebf30da2d8..b6d378a5fe1 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -271,14 +271,17 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
                         let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
                         fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
                     } else {
+                        // Based on LLVM's instruction sequence for compiling
+                        // a.checked_mul(b).is_some() to riscv64gc:
+                        // mulh    a2, a0, a1
+                        // mul     a0, a0, a1
+                        // srai    a0, a0, 63
+                        // xor     a0, a0, a2
+                        // snez    a0, a0
                         let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
-                        let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);
-                        let not_all_ones = fx.bcx.ins().icmp_imm(
-                            IntCC::NotEqual,
-                            val_hi,
-                            u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64,
-                        );
-                        fx.bcx.ins().band(not_all_zero, not_all_ones)
+                        let val_sign = fx.bcx.ins().sshr_imm(val, i64::from(ty.bits() - 1));
+                        let xor = fx.bcx.ins().bxor(val_hi, val_sign);
+                        fx.bcx.ins().icmp_imm(IntCC::NotEqual, xor, 0)
                     };
                     (val, has_overflow)
                 }
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs b/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs
deleted file mode 100644
index ca9ff15ec10..00000000000
--- a/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-//! This optimization moves cold code to the end of the function.
-//!
-//! Some code is executed much less often than other code. For example panicking or the
-//! landingpads for unwinding. By moving this cold code to the end of the function the average
-//! amount of jumps is reduced and the code locality is improved.
-//!
-//! # Undefined behaviour
-//!
-//! This optimization doesn't assume anything that isn't already assumed by Cranelift itself.
-
-use crate::prelude::*;
-
-pub(super) fn optimize_function(ctx: &mut Context, cold_blocks: &EntitySet<Block>) {
-    // FIXME Move the block in place instead of remove and append once
-    // bytecodealliance/cranelift#1339 is implemented.
-
-    let mut block_insts = FxHashMap::default();
-    for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) {
-        let insts = ctx.func.layout.block_insts(block).collect::<Vec<_>>();
-        for &inst in &insts {
-            ctx.func.layout.remove_inst(inst);
-        }
-        block_insts.insert(block, insts);
-        ctx.func.layout.remove_block(block);
-    }
-
-    // And then append them at the back again.
-    for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) {
-        ctx.func.layout.append_block(block);
-        for inst in block_insts.remove(&block).unwrap() {
-            ctx.func.layout.append_inst(inst, block);
-        }
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/mod.rs b/compiler/rustc_codegen_cranelift/src/optimize/mod.rs
index 389f50e797e..137fb5f7731 100644
--- a/compiler/rustc_codegen_cranelift/src/optimize/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/optimize/mod.rs
@@ -2,29 +2,16 @@
 
 use crate::prelude::*;
 
-mod code_layout;
 pub(crate) mod peephole;
-mod stack2reg;
 
 pub(crate) fn optimize_function<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
     ctx: &mut Context,
-    cold_blocks: &EntitySet<Block>,
     clif_comments: &mut crate::pretty_clif::CommentWriter,
 ) {
-    // The code_layout optimization is very cheap.
-    self::code_layout::optimize_function(ctx, cold_blocks);
+    // FIXME classify optimizations over opt levels once we have more
 
-    if tcx.sess.opts.optimize == rustc_session::config::OptLevel::No {
-        return; // FIXME classify optimizations over opt levels
-    }
-
-    // FIXME(#1142) stack2reg miscompiles lewton
-    if false {
-        self::stack2reg::optimize_function(ctx, clif_comments);
-    }
-
-    crate::pretty_clif::write_clif_file(tcx, "stack2reg", None, instance, &ctx, &*clif_comments);
+    crate::pretty_clif::write_clif_file(tcx, "preopt", None, instance, &ctx, &*clif_comments);
     crate::base::verify_func(tcx, &*clif_comments, &ctx.func);
 }
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs b/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs
deleted file mode 100644
index 8bb02a3e558..00000000000
--- a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs
+++ /dev/null
@@ -1,486 +0,0 @@
-//! This optimization replaces stack accesses with SSA variables and removes dead stores when possible.
-//!
-//! # Undefined behaviour
-//!
-//! This optimization is based on the assumption that stack slots which don't have their address
-//! leaked through `stack_addr` are only accessed using `stack_load` and `stack_store` in the
-//! function which has the stack slots. This optimization also assumes that stack slot accesses
-//! are never out of bounds. If these assumptions are not correct, then this optimization may remove
-//! `stack_store` instruction incorrectly, or incorrectly use a previously stored value as the value
-//! being loaded by a `stack_load`.
-
-use std::collections::BTreeMap;
-use std::fmt;
-use std::ops::Not;
-
-use rustc_data_structures::fx::FxHashSet;
-
-use cranelift_codegen::cursor::{Cursor, FuncCursor};
-use cranelift_codegen::ir::immediates::Offset32;
-use cranelift_codegen::ir::{InstructionData, Opcode, ValueDef};
-
-use crate::prelude::*;
-
-/// Workaround for `StackSlot` not implementing `Ord`.
-#[derive(Copy, Clone, PartialEq, Eq)]
-struct OrdStackSlot(StackSlot);
-
-impl fmt::Debug for OrdStackSlot {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-impl PartialOrd for OrdStackSlot {
-    fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering> {
-        self.0.as_u32().partial_cmp(&rhs.0.as_u32())
-    }
-}
-
-impl Ord for OrdStackSlot {
-    fn cmp(&self, rhs: &Self) -> std::cmp::Ordering {
-        self.0.as_u32().cmp(&rhs.0.as_u32())
-    }
-}
-
-#[derive(Debug, Default)]
-struct StackSlotUsage {
-    stack_addr: FxHashSet<Inst>,
-    stack_load: FxHashSet<Inst>,
-    stack_store: FxHashSet<Inst>,
-}
-
-impl StackSlotUsage {
-    fn potential_stores_for_load(&self, ctx: &Context, load: Inst) -> Vec<Inst> {
-        self.stack_store
-            .iter()
-            .cloned()
-            .filter(|&store| {
-                match spatial_overlap(&ctx.func, store, load) {
-                    SpatialOverlap::No => false, // Can never be the source of the loaded value.
-                    SpatialOverlap::Partial | SpatialOverlap::Full => true,
-                }
-            })
-            .filter(|&store| {
-                match temporal_order(ctx, store, load) {
-                    TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value.
-                    TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true,
-                }
-            })
-            .collect::<Vec<Inst>>()
-    }
-
-    fn potential_loads_of_store(&self, ctx: &Context, store: Inst) -> Vec<Inst> {
-        self.stack_load
-            .iter()
-            .cloned()
-            .filter(|&load| {
-                match spatial_overlap(&ctx.func, store, load) {
-                    SpatialOverlap::No => false, // Can never be the source of the loaded value.
-                    SpatialOverlap::Partial | SpatialOverlap::Full => true,
-                }
-            })
-            .filter(|&load| {
-                match temporal_order(ctx, store, load) {
-                    TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value.
-                    TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true,
-                }
-            })
-            .collect::<Vec<Inst>>()
-    }
-
-    fn remove_unused_stack_addr(func: &mut Function, inst: Inst) {
-        func.dfg.detach_results(inst);
-        func.dfg.replace(inst).nop();
-    }
-
-    fn remove_unused_load(func: &mut Function, load: Inst) {
-        func.dfg.detach_results(load);
-        func.dfg.replace(load).nop();
-    }
-
-    fn remove_dead_store(&mut self, func: &mut Function, store: Inst) {
-        func.dfg.replace(store).nop();
-        self.stack_store.remove(&store);
-    }
-
-    fn change_load_to_alias(&mut self, func: &mut Function, load: Inst, value: Value) {
-        let loaded_value = func.dfg.inst_results(load)[0];
-        let loaded_type = func.dfg.value_type(loaded_value);
-
-        if func.dfg.value_type(value) == loaded_type {
-            func.dfg.detach_results(load);
-            func.dfg.replace(load).nop();
-            func.dfg.change_to_alias(loaded_value, value);
-        } else {
-            func.dfg.replace(load).bitcast(loaded_type, value);
-        }
-
-        self.stack_load.remove(&load);
-    }
-}
-
-struct OptimizeContext<'a> {
-    ctx: &'a mut Context,
-    stack_slot_usage_map: BTreeMap<OrdStackSlot, StackSlotUsage>,
-}
-
-impl<'a> OptimizeContext<'a> {
-    fn for_context(ctx: &'a mut Context) -> Self {
-        ctx.flowgraph(); // Compute cfg and domtree.
-
-        // Record all stack_addr, stack_load and stack_store instructions.
-        let mut stack_slot_usage_map = BTreeMap::<OrdStackSlot, StackSlotUsage>::new();
-
-        let mut cursor = FuncCursor::new(&mut ctx.func);
-        while let Some(_block) = cursor.next_block() {
-            while let Some(inst) = cursor.next_inst() {
-                match cursor.func.dfg[inst] {
-                    InstructionData::StackLoad {
-                        opcode: Opcode::StackAddr,
-                        stack_slot,
-                        offset: _,
-                    } => {
-                        stack_slot_usage_map
-                            .entry(OrdStackSlot(stack_slot))
-                            .or_insert_with(StackSlotUsage::default)
-                            .stack_addr
-                            .insert(inst);
-                    }
-                    InstructionData::StackLoad {
-                        opcode: Opcode::StackLoad,
-                        stack_slot,
-                        offset: _,
-                    } => {
-                        stack_slot_usage_map
-                            .entry(OrdStackSlot(stack_slot))
-                            .or_insert_with(StackSlotUsage::default)
-                            .stack_load
-                            .insert(inst);
-                    }
-                    InstructionData::StackStore {
-                        opcode: Opcode::StackStore,
-                        arg: _,
-                        stack_slot,
-                        offset: _,
-                    } => {
-                        stack_slot_usage_map
-                            .entry(OrdStackSlot(stack_slot))
-                            .or_insert_with(StackSlotUsage::default)
-                            .stack_store
-                            .insert(inst);
-                    }
-                    _ => {}
-                }
-            }
-        }
-
-        OptimizeContext { ctx, stack_slot_usage_map }
-    }
-}
-
-pub(super) fn optimize_function(
-    ctx: &mut Context,
-    clif_comments: &mut crate::pretty_clif::CommentWriter,
-) {
-    combine_stack_addr_with_load_store(&mut ctx.func);
-
-    let mut opt_ctx = OptimizeContext::for_context(ctx);
-
-    // FIXME Repeat following instructions until fixpoint.
-
-    remove_unused_stack_addr_and_stack_load(&mut opt_ctx);
-
-    if clif_comments.enabled() {
-        for (&OrdStackSlot(stack_slot), usage) in &opt_ctx.stack_slot_usage_map {
-            clif_comments.add_comment(stack_slot, format!("used by: {:?}", usage));
-        }
-    }
-
-    for (stack_slot, users) in opt_ctx.stack_slot_usage_map.iter_mut() {
-        if users.stack_addr.is_empty().not() {
-            // Stack addr leaked; there may be unknown loads and stores.
-            // FIXME use stacked borrows to optimize
-            continue;
-        }
-
-        for load in users.stack_load.clone().into_iter() {
-            let potential_stores = users.potential_stores_for_load(&opt_ctx.ctx, load);
-
-            if clif_comments.enabled() {
-                for &store in &potential_stores {
-                    clif_comments.add_comment(
-                        load,
-                        format!(
-                            "Potential store -> load forwarding {} -> {} ({:?}, {:?})",
-                            opt_ctx.ctx.func.dfg.display_inst(store, None),
-                            opt_ctx.ctx.func.dfg.display_inst(load, None),
-                            spatial_overlap(&opt_ctx.ctx.func, store, load),
-                            temporal_order(&opt_ctx.ctx, store, load),
-                        ),
-                    );
-                }
-            }
-
-            match *potential_stores {
-                [] => {
-                    if clif_comments.enabled() {
-                        clif_comments
-                            .add_comment(load, "[BUG?] Reading uninitialized memory".to_string());
-                    }
-                }
-                [store]
-                    if spatial_overlap(&opt_ctx.ctx.func, store, load) == SpatialOverlap::Full
-                        && temporal_order(&opt_ctx.ctx, store, load)
-                            == TemporalOrder::DefinitivelyBefore =>
-                {
-                    // Only one store could have been the origin of the value.
-                    let stored_value = opt_ctx.ctx.func.dfg.inst_args(store)[0];
-
-                    if clif_comments.enabled() {
-                        clif_comments.add_comment(
-                            load,
-                            format!("Store to load forward {} -> {}", store, load),
-                        );
-                    }
-
-                    users.change_load_to_alias(&mut opt_ctx.ctx.func, load, stored_value);
-                }
-                _ => {} // FIXME implement this
-            }
-        }
-
-        for store in users.stack_store.clone().into_iter() {
-            let potential_loads = users.potential_loads_of_store(&opt_ctx.ctx, store);
-
-            if clif_comments.enabled() {
-                for &load in &potential_loads {
-                    clif_comments.add_comment(
-                        store,
-                        format!(
-                            "Potential load from store {} <- {} ({:?}, {:?})",
-                            opt_ctx.ctx.func.dfg.display_inst(load, None),
-                            opt_ctx.ctx.func.dfg.display_inst(store, None),
-                            spatial_overlap(&opt_ctx.ctx.func, store, load),
-                            temporal_order(&opt_ctx.ctx, store, load),
-                        ),
-                    );
-                }
-            }
-
-            if potential_loads.is_empty() {
-                // Never loaded; can safely remove all stores and the stack slot.
-                // FIXME also remove stores when there is always a next store before a load.
-
-                if clif_comments.enabled() {
-                    clif_comments.add_comment(
-                        store,
-                        format!(
-                            "Remove dead stack store {} of {}",
-                            opt_ctx.ctx.func.dfg.display_inst(store, None),
-                            stack_slot.0
-                        ),
-                    );
-                }
-
-                users.remove_dead_store(&mut opt_ctx.ctx.func, store);
-            }
-        }
-
-        if users.stack_store.is_empty() && users.stack_load.is_empty() {
-            opt_ctx.ctx.func.stack_slots[stack_slot.0].size = 0;
-        }
-    }
-}
-
-fn combine_stack_addr_with_load_store(func: &mut Function) {
-    // Turn load and store into stack_load and stack_store when possible.
-    let mut cursor = FuncCursor::new(func);
-    while let Some(_block) = cursor.next_block() {
-        while let Some(inst) = cursor.next_inst() {
-            match cursor.func.dfg[inst] {
-                InstructionData::Load { opcode: Opcode::Load, arg: addr, flags: _, offset } => {
-                    if cursor.func.dfg.ctrl_typevar(inst) == types::I128
-                        || cursor.func.dfg.ctrl_typevar(inst).is_vector()
-                    {
-                        continue; // WORKAROUD: stack_load.i128 not yet implemented
-                    }
-                    if let Some((stack_slot, stack_addr_offset)) =
-                        try_get_stack_slot_and_offset_for_addr(cursor.func, addr)
-                    {
-                        if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into())
-                        {
-                            let ty = cursor.func.dfg.ctrl_typevar(inst);
-                            cursor.func.dfg.replace(inst).stack_load(
-                                ty,
-                                stack_slot,
-                                combined_offset,
-                            );
-                        }
-                    }
-                }
-                InstructionData::Store {
-                    opcode: Opcode::Store,
-                    args: [value, addr],
-                    flags: _,
-                    offset,
-                } => {
-                    if cursor.func.dfg.ctrl_typevar(inst) == types::I128
-                        || cursor.func.dfg.ctrl_typevar(inst).is_vector()
-                    {
-                        continue; // WORKAROUND: stack_store.i128 not yet implemented
-                    }
-                    if let Some((stack_slot, stack_addr_offset)) =
-                        try_get_stack_slot_and_offset_for_addr(cursor.func, addr)
-                    {
-                        if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into())
-                        {
-                            cursor.func.dfg.replace(inst).stack_store(
-                                value,
-                                stack_slot,
-                                combined_offset,
-                            );
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-    }
-}
-
-fn remove_unused_stack_addr_and_stack_load(opt_ctx: &mut OptimizeContext<'_>) {
-    // FIXME incrementally rebuild on each call?
-    let mut stack_addr_load_insts_users = FxHashMap::<Inst, FxHashSet<Inst>>::default();
-
-    let mut cursor = FuncCursor::new(&mut opt_ctx.ctx.func);
-    while let Some(_block) = cursor.next_block() {
-        while let Some(inst) = cursor.next_inst() {
-            for &arg in cursor.func.dfg.inst_args(inst) {
-                if let ValueDef::Result(arg_origin, 0) = cursor.func.dfg.value_def(arg) {
-                    match cursor.func.dfg[arg_origin].opcode() {
-                        Opcode::StackAddr | Opcode::StackLoad => {
-                            stack_addr_load_insts_users
-                                .entry(arg_origin)
-                                .or_insert_with(FxHashSet::default)
-                                .insert(inst);
-                        }
-                        _ => {}
-                    }
-                }
-            }
-        }
-    }
-
-    #[cfg(debug_assertions)]
-    for inst in stack_addr_load_insts_users.keys() {
-        let mut is_recorded_stack_addr_or_stack_load = false;
-        for stack_slot_users in opt_ctx.stack_slot_usage_map.values() {
-            is_recorded_stack_addr_or_stack_load |= stack_slot_users.stack_addr.contains(inst)
-                || stack_slot_users.stack_load.contains(inst);
-        }
-        assert!(is_recorded_stack_addr_or_stack_load);
-    }
-
-    // Replace all unused stack_addr and stack_load instructions with nop.
-    let mut func = &mut opt_ctx.ctx.func;
-
-    for stack_slot_users in opt_ctx.stack_slot_usage_map.values_mut() {
-        stack_slot_users
-            .stack_addr
-            .drain_filter(|inst| {
-                stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true)
-            })
-            .for_each(|inst| StackSlotUsage::remove_unused_stack_addr(&mut func, inst));
-
-        stack_slot_users
-            .stack_load
-            .drain_filter(|inst| {
-                stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true)
-            })
-            .for_each(|inst| StackSlotUsage::remove_unused_load(&mut func, inst));
-    }
-}
-
-fn try_get_stack_slot_and_offset_for_addr(
-    func: &Function,
-    addr: Value,
-) -> Option<(StackSlot, Offset32)> {
-    if let ValueDef::Result(addr_inst, 0) = func.dfg.value_def(addr) {
-        if let InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset } =
-            func.dfg[addr_inst]
-        {
-            return Some((stack_slot, offset));
-        }
-    }
-    None
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum SpatialOverlap {
-    No,
-    Partial,
-    Full,
-}
-
-fn spatial_overlap(func: &Function, src: Inst, dest: Inst) -> SpatialOverlap {
-    fn inst_info(func: &Function, inst: Inst) -> (StackSlot, Offset32, u32) {
-        match func.dfg[inst] {
-            InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset }
-            | InstructionData::StackLoad { opcode: Opcode::StackLoad, stack_slot, offset }
-            | InstructionData::StackStore {
-                opcode: Opcode::StackStore,
-                stack_slot,
-                offset,
-                arg: _,
-            } => (stack_slot, offset, func.dfg.ctrl_typevar(inst).bytes()),
-            _ => unreachable!("{:?}", func.dfg[inst]),
-        }
-    }
-
-    debug_assert_ne!(src, dest);
-
-    let (src_ss, src_offset, src_size) = inst_info(func, src);
-    let (dest_ss, dest_offset, dest_size) = inst_info(func, dest);
-
-    if src_ss != dest_ss {
-        return SpatialOverlap::No;
-    }
-
-    if src_offset == dest_offset && src_size == dest_size {
-        return SpatialOverlap::Full;
-    }
-
-    let src_end: i64 = src_offset.try_add_i64(i64::from(src_size)).unwrap().into();
-    let dest_end: i64 = dest_offset.try_add_i64(i64::from(dest_size)).unwrap().into();
-    if src_end <= dest_offset.into() || dest_end <= src_offset.into() {
-        return SpatialOverlap::No;
-    }
-
-    SpatialOverlap::Partial
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum TemporalOrder {
-    /// `src` will never be executed before `dest`.
-    NeverBefore,
-
-    /// `src` may be executed before `dest`.
-    MaybeBefore,
-
-    /// `src` will always be executed before `dest`.
-    /// There may still be other instructions in between.
-    DefinitivelyBefore,
-}
-
-fn temporal_order(ctx: &Context, src: Inst, dest: Inst) -> TemporalOrder {
-    debug_assert_ne!(src, dest);
-
-    if ctx.domtree.dominates(src, dest, &ctx.func.layout) {
-        TemporalOrder::DefinitivelyBefore
-    } else if ctx.domtree.dominates(src, dest, &ctx.func.layout) {
-        TemporalOrder::NeverBefore
-    } else {
-        TemporalOrder::MaybeBefore
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index d22ea3772ee..158811c5eaf 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -207,7 +207,7 @@ pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
 
 pub(crate) fn write_ir_file(
     tcx: TyCtxt<'_>,
-    name: &str,
+    name: impl FnOnce() -> String,
     write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
 ) {
     if !should_write_ir(tcx) {
@@ -222,7 +222,7 @@ pub(crate) fn write_ir_file(
         res @ Err(_) => res.unwrap(),
     }
 
-    let clif_file_name = clif_output_dir.join(name);
+    let clif_file_name = clif_output_dir.join(name());
 
     let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
     if let Err(err) = res {
@@ -238,30 +238,31 @@ pub(crate) fn write_clif_file<'tcx>(
     context: &cranelift_codegen::Context,
     mut clif_comments: &CommentWriter,
 ) {
-    write_ir_file(tcx, &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), |file| {
-        let value_ranges =
-            isa.map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
+    write_ir_file(
+        tcx,
+        || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
+        |file| {
+            let value_ranges = isa
+                .map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
 
-        let mut clif = String::new();
-        cranelift_codegen::write::decorate_function(
-            &mut clif_comments,
-            &mut clif,
-            &context.func,
-            &DisplayFunctionAnnotations {
-                isa: Some(&*crate::build_isa(tcx.sess)),
-                value_ranges: value_ranges.as_ref(),
-            },
-        )
-        .unwrap();
+            let mut clif = String::new();
+            cranelift_codegen::write::decorate_function(
+                &mut clif_comments,
+                &mut clif,
+                &context.func,
+                &DisplayFunctionAnnotations { isa, value_ranges: value_ranges.as_ref() },
+            )
+            .unwrap();
 
-        writeln!(file, "test compile")?;
-        writeln!(file, "set is_pic")?;
-        writeln!(file, "set enable_simd")?;
-        writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
-        writeln!(file)?;
-        file.write_all(clif.as_bytes())?;
-        Ok(())
-    });
+            writeln!(file, "test compile")?;
+            writeln!(file, "set is_pic")?;
+            writeln!(file, "set enable_simd")?;
+            writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
+            writeln!(file)?;
+            file.write_all(clif.as_bytes())?;
+            Ok(())
+        },
+    );
 }
 
 impl fmt::Debug for FunctionCx<'_, '_, '_> {
diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs
index 1ab0703e981..819c8b51558 100644
--- a/compiler/rustc_codegen_cranelift/src/trap.rs
+++ b/compiler/rustc_codegen_cranelift/src/trap.rs
@@ -4,7 +4,6 @@ use crate::prelude::*;
 
 fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
     let puts = fx
-        .cx
         .module
         .declare_function(
             "puts",
@@ -16,13 +15,12 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
             },
         )
         .unwrap();
-    let puts = fx.cx.module.declare_func_in_func(puts, &mut fx.bcx.func);
+    let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(puts, "puts");
     }
 
-    let symbol_name = fx.tcx.symbol_name(fx.instance);
-    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg);
+    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg);
     let msg_ptr = fx.anonymous_str("trap", &real_msg);
     fx.bcx.ins().call(puts, &[msg_ptr]);
 }
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index b97d3900984..9a572c3501f 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -554,7 +554,7 @@ impl<'tcx> CPlace<'tcx> {
                 let src_align = src_layout.align.abi.bytes() as u8;
                 let dst_align = dst_layout.align.abi.bytes() as u8;
                 fx.bcx.emit_small_memory_copy(
-                    fx.cx.module.target_config(),
+                    fx.module.target_config(),
                     to_addr,
                     from_addr,
                     size,
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 9053d1aa1b0..bbf07ffc85d 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -72,15 +72,15 @@ pub(crate) fn get_vtable<'tcx>(
     layout: TyAndLayout<'tcx>,
     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
 ) -> Value {
-    let data_id = if let Some(data_id) = fx.cx.vtables.get(&(layout.ty, trait_ref)) {
+    let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
         *data_id
     } else {
         let data_id = build_vtable(fx, layout, trait_ref);
-        fx.cx.vtables.insert((layout.ty, trait_ref), data_id);
+        fx.vtables.insert((layout.ty, trait_ref), data_id);
         data_id
     };
 
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
 }
 
@@ -94,7 +94,7 @@ fn build_vtable<'tcx>(
 
     let drop_in_place_fn = import_function(
         tcx,
-        fx.cx.module,
+        fx.module,
         Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
     );
 
@@ -111,7 +111,7 @@ fn build_vtable<'tcx>(
         opt_mth.map(|(def_id, substs)| {
             import_function(
                 tcx,
-                fx.cx.module,
+                fx.module,
                 Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
                     .unwrap()
                     .polymorphize(fx.tcx),
@@ -132,34 +132,16 @@ fn build_vtable<'tcx>(
 
     for (i, component) in components.into_iter().enumerate() {
         if let Some(func_id) = component {
-            let func_ref = fx.cx.module.declare_func_in_data(func_id, &mut data_ctx);
+            let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
             data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
         }
     }
 
     data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes());
 
-    let data_id = fx
-        .cx
-        .module
-        .declare_data(
-            &format!(
-                "__vtable.{}.for.{:?}.{}",
-                trait_ref
-                    .as_ref()
-                    .map(|trait_ref| format!("{:?}", trait_ref.skip_binder()).into())
-                    .unwrap_or(std::borrow::Cow::Borrowed("???")),
-                layout.ty,
-                fx.cx.vtables.len(),
-            ),
-            Linkage::Local,
-            false,
-            false,
-        )
-        .unwrap();
-
-    // FIXME don't duplicate definitions in lazy jit mode
-    let _ = fx.cx.module.define_data(data_id, &data_ctx);
+    let data_id = fx.module.declare_anonymous_data(false, false).unwrap();
+
+    fx.module.define_data(data_id, &data_ctx).unwrap();
 
     data_id
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 2ac814bf228..1faaa7e86f6 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -8,6 +8,7 @@ use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE};
 use rustc_llvm::RustString;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::CodeRegion;
 use rustc_span::Symbol;
 
@@ -280,6 +281,10 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
 
     let mut unused_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default();
     for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) {
+        let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+            continue;
+        }
         // Make sure the non-codegenned (unused) function has a file_name
         if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
             let def_ids =
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index e6fa852155b..280d9a4d370 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -309,6 +309,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> {
                     unfinished_type,
                     member_holding_stub,
                     member_descriptions,
+                    None,
                 );
                 MetadataCreationResult::new(metadata_stub, true)
             }
@@ -1459,6 +1460,7 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
     layout: TyAndLayout<'tcx>,
     tag_type_metadata: Option<&'ll DIType>,
     containing_scope: &'ll DIScope,
+    common_members: Vec<Option<&'ll DIType>>,
     span: Span,
 }
 
@@ -1493,10 +1495,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
         } else {
             type_metadata(cx, self.enum_type, self.span)
         };
-        let flags = match self.enum_type.kind() {
-            ty::Generator(..) => DIFlags::FlagArtificial,
-            _ => DIFlags::FlagZero,
-        };
 
         match self.layout.variants {
             Variants::Single { index } => {
@@ -1523,6 +1521,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                     self.enum_type,
                     variant_type_metadata,
                     member_descriptions,
+                    Some(&self.common_members),
                 );
                 vec![MemberDescription {
                     name: if fallback { String::new() } else { variant_info.variant_name() },
@@ -1530,7 +1529,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                     offset: Size::ZERO,
                     size: self.layout.size,
                     align: self.layout.align.abi,
-                    flags,
+                    flags: DIFlags::FlagZero,
                     discriminant: None,
                     source_info: variant_info.source_info(cx),
                 }]
@@ -1572,6 +1571,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                             self.enum_type,
                             variant_type_metadata,
                             member_descriptions,
+                            Some(&self.common_members),
                         );
 
                         MemberDescription {
@@ -1584,7 +1584,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                             offset: Size::ZERO,
                             size: self.layout.size,
                             align: self.layout.align.abi,
-                            flags,
+                            flags: DIFlags::FlagZero,
                             discriminant: Some(
                                 self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val
                                     as u64,
@@ -1621,6 +1621,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                         self.enum_type,
                         variant_type_metadata,
                         variant_member_descriptions,
+                        Some(&self.common_members),
                     );
 
                     // Encode the information about the null variant in the union
@@ -1667,7 +1668,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                         offset: Size::ZERO,
                         size: variant.size,
                         align: variant.align.abi,
-                        flags,
+                        flags: DIFlags::FlagZero,
                         discriminant: None,
                         source_info: variant_info.source_info(cx),
                     }]
@@ -1695,6 +1696,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                 self.enum_type,
                                 variant_type_metadata,
                                 member_descriptions,
+                                Some(&self.common_members),
                             );
 
                             let niche_value = if i == dataful_variant {
@@ -1717,7 +1719,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                 offset: Size::ZERO,
                                 size: self.layout.size,
                                 align: self.layout.align.abi,
-                                flags,
+                                flags: DIFlags::FlagZero,
                                 discriminant: niche_value,
                                 source_info: variant_info.source_info(cx),
                             }
@@ -1849,13 +1851,6 @@ impl<'tcx> VariantInfo<'_, 'tcx> {
         }
         None
     }
-
-    fn is_artificial(&self) -> bool {
-        match self {
-            VariantInfo::Generator { .. } => true,
-            VariantInfo::Adt(..) => false,
-        }
-    }
 }
 
 /// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a
@@ -1881,8 +1876,7 @@ fn describe_enum_variant(
             &variant_name,
             unique_type_id,
             Some(containing_scope),
-            // FIXME(tmandry): This doesn't seem to have any effect.
-            if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero },
+            DIFlags::FlagZero,
         )
     });
 
@@ -1945,11 +1939,6 @@ fn prepare_enum_metadata(
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tcx = cx.tcx;
     let enum_name = compute_debuginfo_type_name(tcx, enum_type, false);
-    // FIXME(tmandry): This doesn't seem to have any effect.
-    let enum_flags = match enum_type.kind() {
-        ty::Generator(..) => DIFlags::FlagArtificial,
-        _ => DIFlags::FlagZero,
-    };
 
     let containing_scope = get_namespace_for_item(cx, enum_def_id);
     // FIXME: This should emit actual file metadata for the enum, but we
@@ -2082,7 +2071,7 @@ fn prepare_enum_metadata(
                     UNKNOWN_LINE_NUMBER,
                     layout.size.bits(),
                     layout.align.abi.bits() as u32,
-                    enum_flags,
+                    DIFlags::FlagZero,
                     None,
                     0, // RuntimeLang
                     unique_type_id_str.as_ptr().cast(),
@@ -2102,6 +2091,7 @@ fn prepare_enum_metadata(
                 layout,
                 tag_type_metadata: discriminant_type_metadata,
                 containing_scope,
+                common_members: vec![],
                 span,
             }),
         );
@@ -2171,7 +2161,7 @@ fn prepare_enum_metadata(
         }
     };
 
-    let mut outer_fields = match layout.variants {
+    let outer_fields = match layout.variants {
         Variants::Single { .. } => vec![],
         Variants::Multiple { .. } => {
             let tuple_mdf = TupleMemberDescriptionFactory {
@@ -2203,18 +2193,21 @@ fn prepare_enum_metadata(
             UNKNOWN_LINE_NUMBER,
             layout.size.bits(),
             layout.align.abi.bits() as u32,
-            enum_flags,
+            DIFlags::FlagZero,
             discriminator_metadata,
             empty_array,
             variant_part_unique_type_id_str.as_ptr().cast(),
             variant_part_unique_type_id_str.len(),
         )
     };
-    outer_fields.push(Some(variant_part));
 
     let struct_wrapper = {
         // The variant part must be wrapped in a struct according to DWARF.
-        let type_array = create_DIArray(DIB(cx), &outer_fields);
+        // All fields except the discriminant (including `outer_fields`)
+        // should be put into structures inside the variant part, which gives
+        // an equivalent layout but offers us much better integration with
+        // debuggers.
+        let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
 
         let type_map = debug_context(cx).type_map.borrow();
         let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
@@ -2229,7 +2222,7 @@ fn prepare_enum_metadata(
                 UNKNOWN_LINE_NUMBER,
                 layout.size.bits(),
                 layout.align.abi.bits() as u32,
-                enum_flags,
+                DIFlags::FlagZero,
                 None,
                 type_array,
                 0,
@@ -2251,6 +2244,7 @@ fn prepare_enum_metadata(
             layout,
             tag_type_metadata: None,
             containing_scope,
+            common_members: outer_fields,
             span,
         }),
     )
@@ -2283,7 +2277,13 @@ fn composite_type_metadata(
         DIFlags::FlagZero,
     );
     // ... and immediately create and add the member descriptions.
-    set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions);
+    set_members_of_composite_type(
+        cx,
+        composite_type,
+        composite_type_metadata,
+        member_descriptions,
+        None,
+    );
 
     composite_type_metadata
 }
@@ -2293,6 +2293,7 @@ fn set_members_of_composite_type(
     composite_type: Ty<'tcx>,
     composite_type_metadata: &'ll DICompositeType,
     member_descriptions: Vec<MemberDescription<'ll>>,
+    common_members: Option<&Vec<Option<&'ll DIType>>>,
 ) {
     // In some rare cases LLVM metadata uniquing would lead to an existing type
     // description being used instead of a new one created in
@@ -2311,10 +2312,13 @@ fn set_members_of_composite_type(
         }
     }
 
-    let member_metadata: Vec<_> = member_descriptions
+    let mut member_metadata: Vec<_> = member_descriptions
         .into_iter()
         .map(|desc| Some(desc.into_metadata(cx, composite_type_metadata)))
         .collect();
+    if let Some(other_members) = common_members {
+        member_metadata.extend(other_members.iter());
+    }
 
     let type_params = compute_type_parameters(cx, composite_type);
     unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index e157a38aa03..b928e903730 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -344,7 +344,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             spflags |= DISPFlags::SPFlagOptimized;
         }
         if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
-            if id.to_def_id() == def_id {
+            if id == def_id {
                 spflags |= DISPFlags::SPFlagMainSubprogram;
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 318eed76acf..e045a23eb0c 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::{par_iter, ParallelIterator};
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -348,12 +348,29 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
 ) -> Option<Bx::Function> {
     let main_def_id = cx.tcx().entry_fn(LOCAL_CRATE).map(|(def_id, _)| def_id)?;
-    let instance = Instance::mono(cx.tcx(), main_def_id.to_def_id());
+    let main_is_local = main_def_id.is_local();
+    let instance = Instance::mono(cx.tcx(), main_def_id);
 
-    if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
+    if main_is_local {
         // We want to create the wrapper in the same codegen unit as Rust's main
         // function.
-        return None;
+        if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
+            return None;
+        }
+    } else {
+        // FIXME: Add support for non-local main fn codegen
+        let span = cx.tcx().main_def.unwrap().span;
+        let n = 28937;
+        cx.sess()
+            .struct_span_err(span, "entry symbol `main` from foreign crate is not yet supported.")
+            .note(&format!(
+                "see issue #{} <https://github.com/rust-lang/rust/issues/{}> \
+                 for more information",
+                n, n,
+            ))
+            .emit();
+        cx.sess().abort_if_errors();
+        bug!();
     }
 
     let main_llfn = cx.get_fn_addr(instance);
@@ -366,7 +383,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         cx: &'a Bx::CodegenCx,
         rust_main: Bx::Value,
-        rust_main_def_id: LocalDefId,
+        rust_main_def_id: DefId,
         use_start_lang_item: bool,
     ) -> Bx::Function {
         // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 507425d64e3..aa95ecbdaf9 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -32,7 +32,6 @@ tempfile = "3.2"
 
 [dependencies.parking_lot]
 version = "0.11"
-features = ["nightly"]
 
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["fileapi", "psapi"] }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0136.md b/compiler/rustc_error_codes/src/error_codes/E0136.md
index b91b52c074c..15cf09a18cb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0136.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0136.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 More than one `main` function was found.
 
 Erroneous code example:
 
-```compile_fail,E0136
+```compile_fail
 fn main() {
     // ...
 }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 529ef7e4611..3347c93948c 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -20,7 +20,7 @@ use rustc_attr::{self as attr, is_builtin_attr};
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, FatalError, PResult};
 use rustc_feature::Features;
 use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser, RecoverComma};
 use rustc_parse::validate_attr;
@@ -414,6 +414,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         kind.article(), kind.descr()
                     ),
                 );
+                // FIXME: this workaround issue #84569
+                FatalError.raise();
             }
         };
         self.cx.trace_macros_diag();
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index bc45c57596e..91d4a0f0d65 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -955,15 +955,15 @@ fn check_matcher_core(
             if let TokenTree::MetaVarDecl(span, name, Some(kind)) = *token {
                 for next_token in &suffix_first.tokens {
                     // Check if the old pat is used and the next token is `|`.
-                    if let NonterminalKind::Pat2015 { inferred: true } = kind {
+                    if let NonterminalKind::PatParam { inferred: true } = kind {
                         if let TokenTree::Token(token) = next_token {
                             if let BinOp(token) = token.kind {
                                 if let token::BinOpToken::Or = token {
-                                    // It is suggestion to use pat2015, for example: $x:pat -> $x:pat2015.
+                                    // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
                                     let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
                                         span,
                                         name,
-                                        Some(NonterminalKind::Pat2015 { inferred: false }),
+                                        Some(NonterminalKind::PatParam { inferred: false }),
                                     ));
                                     sess.buffer_lint_with_diagnostic(
                                         &OR_PATTERNS_BACK_COMPAT,
@@ -1105,7 +1105,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                     _ => IsInFollow::No(TOKENS),
                 }
             }
-            NonterminalKind::Pat2015 { .. } => {
+            NonterminalKind::PatParam { .. } => {
                 const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
                 match tok {
                     TokenTree::Token(token) => match token.kind {
@@ -1116,7 +1116,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                     _ => IsInFollow::No(TOKENS),
                 }
             }
-            NonterminalKind::Pat2021 { .. } => {
+            NonterminalKind::PatWithOr { .. } => {
                 const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
                 match tok {
                     TokenTree::Token(token) => match token.kind {
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index e205cb65d02..aca02ef93f8 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -6,8 +6,8 @@ use rustc_ast::tokenstream;
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_feature::Features;
-use rustc_session::parse::{feature_err, ParseSess};
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_session::parse::ParseSess;
+use rustc_span::symbol::{kw, Ident};
 
 use rustc_span::Span;
 
@@ -62,21 +62,6 @@ pub(super) fn parse(
                                 Some((frag, _)) => {
                                     let span = token.span.with_lo(start_sp.lo());
 
-                                    match frag.name {
-                                        sym::pat2015 | sym::pat2021 => {
-                                            if !features.edition_macro_pats {
-                                                feature_err(
-                                                    sess,
-                                                    sym::edition_macro_pats,
-                                                    frag.span,
-                                                    "`pat2015` and `pat2021` are unstable.",
-                                                )
-                                                .emit();
-                                            }
-                                        }
-                                        _ => {}
-                                    }
-
                                     let kind =
                                         token::NonterminalKind::from_symbol(frag.name, || {
                                             span.edition()
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 304d7ede625..4ad5f085ad0 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -607,9 +607,6 @@ declare_features! (
     /// Allows arbitrary expressions in key-value attributes at parse time.
     (active, extended_key_value_attributes, "1.50.0", Some(78835), None),
 
-    /// `:pat2015` and `:pat2021` macro matchers.
-    (active, edition_macro_pats, "1.51.0", Some(54883), None),
-
     /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
     (active, const_generics_defaults, "1.51.0", Some(44580), None),
 
@@ -646,12 +643,19 @@ declare_features! (
     /// Allows `extern "wasm" fn`
     (active, wasm_abi, "1.53.0", Some(83788), None),
 
+    /// Allows function attribute `#[no_coverage]`, to bypass coverage
+    /// instrumentation of that function.
+    (active, no_coverage, "1.53.0", Some(84605), None),
+
     /// Allows trait bounds in `const fn`.
     (active, const_fn_trait_bound, "1.53.0", Some(57563), None),
 
     /// Allows unsizing coercions in `const fn`.
     (active, const_fn_unsize, "1.53.0", Some(64992), None),
 
+    /// Allows using imported `main` function
+    (active, imported_main, "1.53.0", Some(28937), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b8a0b8debcd..5474fea9c78 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -273,6 +273,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(List: "address, memory, thread"),
         experimental!(no_sanitize)
     ),
+    ungated!(
+        // Not exclusively gated at the crate level (though crate-level is
+        // supported). The feature can alternatively be enabled on individual
+        // functions.
+        no_coverage, AssumedUsed,
+        template!(Word),
+    ),
 
     // FIXME: #14408 assume docs are used since rustdoc looks at them.
     ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 259e540c612..2661afd7ffc 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -104,7 +104,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     // Fortunately, we just checked that this isn't the case.
     let path = dep_graph_path_from(&sess.incr_comp_session_dir());
     let report_incremental_info = sess.opts.debugging_opts.incremental_info;
-    let expected_hash = sess.opts.dep_tracking_hash();
+    let expected_hash = sess.opts.dep_tracking_hash(false);
 
     let mut prev_work_products = FxHashMap::default();
     let nightly_build = sess.is_nightly_build();
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index d558af3c1d5..1484088837a 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -219,7 +219,7 @@ pub fn build_dep_graph(
     }
 
     // First encode the commandline arguments hash
-    if let Err(err) = sess.opts.dep_tracking_hash().encode(&mut encoder) {
+    if let Err(err) = sess.opts.dep_tracking_hash(false).encode(&mut encoder) {
         sess.err(&format!(
             "failed to write dependency graph hash `{}`: {}",
             path_buf.display(),
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 87684c2715f..1cde4802a40 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -305,9 +305,7 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
                     Some(assoc_name),
                 ));
                 for (super_predicate, _) in super_predicates.predicates {
-                    let bound_predicate = super_predicate.kind();
-                    let subst_predicate = super_predicate
-                        .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder()));
+                    let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
                     if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
                         stack.push(binder.value);
                     }
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 01853eab530..bc94fb67ac3 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -307,7 +307,7 @@ impl<'tcx> Queries<'tcx> {
             _ => return,
         };
 
-        let attrs = &*tcx.get_attrs(def_id.to_def_id());
+        let attrs = &*tcx.get_attrs(def_id);
         let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error));
         for attr in attrs {
             match attr.meta_item_list() {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 9685d21762b..d8c1a7a2682 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -19,6 +19,7 @@ use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
 use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, TlsModel};
+
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
 use std::num::NonZeroUsize;
@@ -74,6 +75,27 @@ fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
     BTreeMap::from_iter(entries.into_iter())
 }
 
+fn assert_same_clone(x: &Options) {
+    assert_eq!(x.dep_tracking_hash(true), x.clone().dep_tracking_hash(true));
+    assert_eq!(x.dep_tracking_hash(false), x.clone().dep_tracking_hash(false));
+}
+
+fn assert_same_hash(x: &Options, y: &Options) {
+    assert_eq!(x.dep_tracking_hash(true), y.dep_tracking_hash(true));
+    assert_eq!(x.dep_tracking_hash(false), y.dep_tracking_hash(false));
+    // Check clone
+    assert_same_clone(x);
+    assert_same_clone(y);
+}
+
+fn assert_different_hash(x: &Options, y: &Options) {
+    assert_ne!(x.dep_tracking_hash(true), y.dep_tracking_hash(true));
+    assert_ne!(x.dep_tracking_hash(false), y.dep_tracking_hash(false));
+    // Check clone
+    assert_same_clone(x);
+    assert_same_clone(y);
+}
+
 // When the user supplies --test we should implicitly supply --cfg test
 #[test]
 fn test_switch_implies_cfg_test() {
@@ -130,14 +152,9 @@ fn test_output_types_tracking_hash_different_paths() {
     v2.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
     v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
 
-    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-    assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v2, &v3);
 }
 
 #[test]
@@ -155,10 +172,7 @@ fn test_output_types_tracking_hash_different_construction_order() {
         (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
     ]);
 
-    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
 }
 
 #[test]
@@ -182,14 +196,9 @@ fn test_externs_tracking_hash_different_construction_order() {
         (String::from("d"), new_public_extern_entry(vec!["f", "e"])),
     ]));
 
-    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-    assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
+    assert_same_hash(&v1, &v3);
+    assert_same_hash(&v2, &v3);
 }
 
 #[test]
@@ -219,14 +228,9 @@ fn test_lints_tracking_hash_different_values() {
         (String::from("d"), Level::Deny),
     ];
 
-    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-    assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v2, &v3);
 }
 
 #[test]
@@ -248,11 +252,7 @@ fn test_lints_tracking_hash_different_construction_order() {
         (String::from("d"), Level::Forbid),
     ];
 
-    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
 }
 
 #[test]
@@ -292,15 +292,9 @@ fn test_search_paths_tracking_hash_different_order() {
     v4.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
     v4.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
 
-    assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
+    assert_same_hash(&v1, &v3);
+    assert_same_hash(&v1, &v4);
 }
 
 #[test]
@@ -338,15 +332,9 @@ fn test_native_libs_tracking_hash_different_values() {
         (String::from("c"), None, NativeLibKind::Unspecified),
     ];
 
-    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v1, &v4);
 }
 
 #[test]
@@ -374,14 +362,9 @@ fn test_native_libs_tracking_hash_different_order() {
         (String::from("b"), None, NativeLibKind::Framework),
     ];
 
-    assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
-    assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
+    assert_same_hash(&v1, &v3);
+    assert_same_hash(&v2, &v3);
 }
 
 #[test]
@@ -391,8 +374,9 @@ fn test_codegen_options_tracking_hash() {
 
     macro_rules! untracked {
         ($name: ident, $non_default_value: expr) => {
+            assert_ne!(opts.cg.$name, $non_default_value);
             opts.cg.$name = $non_default_value;
-            assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_same_hash(&reference, &opts);
         };
     }
 
@@ -416,8 +400,9 @@ fn test_codegen_options_tracking_hash() {
     macro_rules! tracked {
         ($name: ident, $non_default_value: expr) => {
             opts = reference.clone();
+            assert_ne!(opts.cg.$name, $non_default_value);
             opts.cg.$name = $non_default_value;
-            assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_different_hash(&reference, &opts);
         };
     }
 
@@ -455,14 +440,41 @@ fn test_codegen_options_tracking_hash() {
 }
 
 #[test]
+fn test_top_level_options_tracked_no_crate() {
+    let reference = Options::default();
+    let mut opts;
+
+    macro_rules! tracked {
+        ($name: ident, $non_default_value: expr) => {
+            opts = reference.clone();
+            assert_ne!(opts.$name, $non_default_value);
+            opts.$name = $non_default_value;
+            // The crate hash should be the same
+            assert_eq!(reference.dep_tracking_hash(true), opts.dep_tracking_hash(true));
+            // The incremental hash should be different
+            assert_ne!(reference.dep_tracking_hash(false), opts.dep_tracking_hash(false));
+        };
+    }
+
+    // Make sure that changing a [TRACKED_NO_CRATE_HASH] option leaves the crate hash unchanged but changes the incremental hash.
+    // This list is in alphabetical order.
+    tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
+    tracked!(
+        real_rust_source_base_dir,
+        Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into())
+    );
+}
+
+#[test]
 fn test_debugging_options_tracking_hash() {
     let reference = Options::default();
     let mut opts = Options::default();
 
     macro_rules! untracked {
         ($name: ident, $non_default_value: expr) => {
+            assert_ne!(opts.debugging_opts.$name, $non_default_value);
             opts.debugging_opts.$name = $non_default_value;
-            assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_same_hash(&reference, &opts);
         };
     }
 
@@ -471,7 +483,7 @@ fn test_debugging_options_tracking_hash() {
     untracked!(ast_json, true);
     untracked!(ast_json_noexpand, true);
     untracked!(borrowck, String::from("other"));
-    untracked!(deduplicate_diagnostics, true);
+    untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
@@ -515,7 +527,7 @@ fn test_debugging_options_tracking_hash() {
     untracked!(self_profile_events, Some(vec![String::new()]));
     untracked!(span_debug, true);
     untracked!(span_free_formats, true);
-    untracked!(strip, Strip::None);
+    untracked!(strip, Strip::Debuginfo);
     untracked!(terminal_width, Some(80));
     untracked!(threads, 99);
     untracked!(time, true);
@@ -532,8 +544,9 @@ fn test_debugging_options_tracking_hash() {
     macro_rules! tracked {
         ($name: ident, $non_default_value: expr) => {
             opts = reference.clone();
+            assert_ne!(opts.debugging_opts.$name, $non_default_value);
             opts.debugging_opts.$name = $non_default_value;
-            assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_different_hash(&reference, &opts);
         };
     }
 
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index b3a19bfbf75..c1d6a4f1de1 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -710,7 +710,7 @@ pub trait LintContext: Sized {
                     db.note(&note);
                 }
                 BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => {
-                    db.span_suggestion(span, "use pat2015 to preserve semantics", suggestion, Applicability::MachineApplicable);
+                    db.span_suggestion(span, "use pat_param to preserve semantics", suggestion, Applicability::MachineApplicable);
                 }
             }
             // Rewrap `db`, and pass control to the user.
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 617b2ed970e..65a988629c3 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -609,7 +609,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
 
   std::string ErrorInfo;
   std::error_code EC;
-  raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+  raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
   if (EC)
     ErrorInfo = EC.message();
   if (ErrorInfo != "") {
@@ -619,7 +619,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
 
   buffer_ostream BOS(OS);
   if (DwoPath) {
-    raw_fd_ostream DOS(DwoPath, EC, sys::fs::F_None);
+    raw_fd_ostream DOS(DwoPath, EC, sys::fs::OF_None);
     EC.clear();
     if (EC)
         ErrorInfo = EC.message();
@@ -1146,7 +1146,7 @@ extern "C" LLVMRustResult
 LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) {
   std::string ErrorInfo;
   std::error_code EC;
-  raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+  raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
   if (EC)
     ErrorInfo = EC.message();
   if (ErrorInfo != "") {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 19ae5ce69c1..2ade1bb4f95 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1617,7 +1617,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .map(Path::new)
             .filter(|_| {
                 // Only spend time on further checks if we have what to translate *to*.
-                sess.real_rust_source_base_dir.is_some()
+                sess.opts.real_rust_source_base_dir.is_some()
             })
             .filter(|virtual_dir| {
                 // Don't translate away `/rustc/$hash` if we're still remapping to it,
@@ -1629,11 +1629,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             debug!(
                 "try_to_translate_virtual_to_real(name={:?}): \
                  virtual_rust_source_base_dir={:?}, real_rust_source_base_dir={:?}",
-                name, virtual_rust_source_base_dir, sess.real_rust_source_base_dir,
+                name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir,
             );
 
             if let Some(virtual_dir) = virtual_rust_source_base_dir {
-                if let Some(real_dir) = &sess.real_rust_source_base_dir {
+                if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
                     if let rustc_span::FileName::Real(old_name) = name {
                         if let rustc_span::RealFileName::Named(one_path) = old_name {
                             if let Ok(rest) = one_path.strip_prefix(virtual_dir) {
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 9a42bbe7bac..d5697513eef 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -91,7 +91,7 @@ macro_rules! arena_types {
             [] predicates: rustc_middle::ty::PredicateInner<$tcx>,
 
             // HIR query types
-            [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>,
+            [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>,
             [few] hir_definitions: rustc_hir::definitions::Definitions,
             [] hir_owner: rustc_middle::hir::Owner<$tcx>,
             [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
index 501e7d624d2..719bbf04c95 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_middle/src/hir/map/collector.rs
@@ -1,22 +1,20 @@
 use crate::arena::Arena;
-use crate::hir::map::{Entry, HirOwnerData, Map};
-use crate::hir::{Owner, OwnerNodes, ParentedNode};
+use crate::hir::map::{HirOwnerData, Map};
+use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode};
 use crate::ich::StableHashingContext;
-use crate::middle::cstore::CrateStore;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
-use rustc_hir::definitions::{self, DefPathHash};
+use rustc_hir::definitions;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::*;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
 
 use std::iter::repeat;
 
@@ -31,6 +29,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     source_map: &'a SourceMap,
 
     map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    parenting: FxHashMap<LocalDefId, HirId>,
 
     /// The parent of this node
     parent_node: hir::HirId,
@@ -40,10 +39,6 @@ pub(super) struct NodeCollector<'a, 'hir> {
     definitions: &'a definitions::Definitions,
 
     hcx: StableHashingContext<'a>,
-
-    // We are collecting HIR hashes here so we can compute the
-    // crate hash from them later on.
-    hir_body_nodes: Vec<(DefPathHash, Fingerprint)>,
 }
 
 fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
@@ -58,34 +53,20 @@ fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V
 
 fn hash_body(
     hcx: &mut StableHashingContext<'_>,
-    def_path_hash: DefPathHash,
     item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
-    hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>,
 ) -> Fingerprint {
-    let hash = {
-        let mut stable_hasher = StableHasher::new();
-        hcx.while_hashing_hir_bodies(true, |hcx| {
-            item_like.hash_stable(hcx, &mut stable_hasher);
-        });
-        stable_hasher.finish()
-    };
-    hir_body_nodes.push((def_path_hash, hash));
-    hash
+    let mut stable_hasher = StableHasher::new();
+    hcx.while_hashing_hir_bodies(true, |hcx| {
+        item_like.hash_stable(hcx, &mut stable_hasher);
+    });
+    stable_hasher.finish()
 }
 
-fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
-    let mut upstream_crates: Vec<_> = cstore
-        .crates_untracked()
-        .iter()
-        .map(|&cnum| {
-            let name = cstore.crate_name_untracked(cnum);
-            let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
-            let hash = cstore.crate_hash_untracked(cnum);
-            (name, disambiguator, hash)
-        })
-        .collect();
-    upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
-    upstream_crates
+/// Represents an entry and its parent `HirId`.
+#[derive(Copy, Clone, Debug)]
+pub struct Entry<'hir> {
+    parent: HirId,
+    node: Node<'hir>,
 }
 
 impl<'a, 'hir> NodeCollector<'a, 'hir> {
@@ -96,11 +77,6 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         definitions: &'a definitions::Definitions,
         mut hcx: StableHashingContext<'a>,
     ) -> NodeCollector<'a, 'hir> {
-        let root_mod_def_path_hash =
-            definitions.def_path_hash(LocalDefId { local_def_index: CRATE_DEF_INDEX });
-
-        let mut hir_body_nodes = Vec::new();
-
         let hash = {
             let Crate {
                 ref item,
@@ -120,7 +96,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                 attrs: _,
             } = *krate;
 
-            hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes)
+            hash_body(&mut hcx, item)
         };
 
         let mut collector = NodeCollector {
@@ -131,10 +107,10 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
             current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
             definitions,
             hcx,
-            hir_body_nodes,
             map: (0..definitions.def_index_count())
                 .map(|_| HirOwnerData { signature: None, with_bodies: None })
                 .collect(),
+            parenting: FxHashMap::default(),
         };
         collector.insert_entry(
             hir::CRATE_HIR_ID,
@@ -145,55 +121,13 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         collector
     }
 
-    pub(super) fn finalize_and_compute_crate_hash(
-        mut self,
-        crate_disambiguator: CrateDisambiguator,
-        cstore: &dyn CrateStore,
-        commandline_args_hash: u64,
-    ) -> (IndexVec<LocalDefId, HirOwnerData<'hir>>, Svh) {
+    pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
         // Insert bodies into the map
         for (id, body) in self.krate.bodies.iter() {
             let bodies = &mut self.map[id.hir_id.owner].with_bodies.as_mut().unwrap().bodies;
             assert!(bodies.insert(id.hir_id.local_id, body).is_none());
         }
-
-        self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
-
-        let node_hashes = self.hir_body_nodes.iter().fold(
-            Fingerprint::ZERO,
-            |combined_fingerprint, &(def_path_hash, fingerprint)| {
-                combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
-            },
-        );
-
-        let upstream_crates = upstream_crates(cstore);
-
-        // We hash the final, remapped names of all local source files so we
-        // don't have to include the path prefix remapping commandline args.
-        // If we included the full mapping in the SVH, we could only have
-        // reproducible builds by compiling from the same directory. So we just
-        // hash the result of the mapping instead of the mapping itself.
-        let mut source_file_names: Vec<_> = self
-            .source_map
-            .files()
-            .iter()
-            .filter(|source_file| source_file.cnum == LOCAL_CRATE)
-            .map(|source_file| source_file.name_hash)
-            .collect();
-
-        source_file_names.sort_unstable();
-
-        let crate_hash_input = (
-            ((node_hashes, upstream_crates), source_file_names),
-            (commandline_args_hash, crate_disambiguator.to_fingerprint()),
-        );
-
-        let mut stable_hasher = StableHasher::new();
-        crate_hash_input.hash_stable(&mut self.hcx, &mut stable_hasher);
-        let crate_hash: Fingerprint = stable_hasher.finish();
-
-        let svh = Svh::new(crate_hash.to_smaller_hash());
-        (self.map, svh)
+        IndexedHir { map: self.map, parenting: self.parenting }
     }
 
     fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
@@ -218,8 +152,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
             nodes.hash = hash;
 
             debug_assert!(data.signature.is_none());
-            data.signature =
-                Some(self.arena.alloc(Owner { parent: entry.parent, node: entry.node }));
+            data.signature = Some(self.arena.alloc(Owner { node: entry.node }));
 
             let dk_parent = self.definitions.def_key(id.owner).parent;
             if let Some(dk_parent) = dk_parent {
@@ -231,6 +164,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                         id.owner, dk_parent, entry.parent,
                     )
                 }
+
+                debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
             }
         } else {
             assert_eq!(entry.parent.owner, id.owner);
@@ -294,15 +229,28 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         f: F,
     ) {
         let prev_owner = self.current_dep_node_owner;
-
-        let def_path_hash = self.definitions.def_path_hash(dep_node_owner);
-
-        let hash = hash_body(&mut self.hcx, def_path_hash, item_like, &mut self.hir_body_nodes);
+        let hash = hash_body(&mut self.hcx, item_like);
 
         self.current_dep_node_owner = dep_node_owner;
         f(self, hash);
         self.current_dep_node_owner = prev_owner;
     }
+
+    fn insert_nested(&mut self, item: LocalDefId) {
+        #[cfg(debug_assertions)]
+        {
+            let dk_parent = self.definitions.def_key(item).parent.unwrap();
+            let dk_parent = LocalDefId { local_def_index: dk_parent };
+            let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
+            debug_assert_eq!(
+                dk_parent.owner, self.parent_node.owner,
+                "Different parents for {:?}",
+                item
+            )
+        }
+
+        assert_eq!(self.parenting.insert(item, self.parent_node), None);
+    }
 }
 
 impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
@@ -318,18 +266,22 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
+        self.insert_nested(item.def_id);
         self.visit_item(self.krate.item(item));
     }
 
     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+        self.insert_nested(item_id.def_id);
         self.visit_trait_item(self.krate.trait_item(item_id));
     }
 
     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
+        self.insert_nested(item_id.def_id);
         self.visit_impl_item(self.krate.impl_item(item_id));
     }
 
     fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
+        self.insert_nested(foreign_id.def_id);
         self.visit_foreign_item(self.krate.foreign_item(foreign_id));
     }
 
@@ -517,6 +469,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
             self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index })
         });
         self.with_parent(parent, |this| {
+            this.insert_nested(macro_def.def_id);
             this.with_dep_node_owner(macro_def.def_id, macro_def, |this, hash| {
                 this.insert_with_hash(
                     macro_def.span,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index d155276051e..73f3b550c37 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,8 +1,11 @@
 use self::collector::NodeCollector;
 
-use crate::hir::{Owner, OwnerNodes};
+use crate::hir::{HirOwnerData, IndexedHir};
+use crate::middle::cstore::CrateStore;
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -11,7 +14,7 @@ use rustc_hir::intravisit;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::Idx;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -21,22 +24,6 @@ use rustc_target::spec::abi::Abi;
 pub mod blocks;
 mod collector;
 
-/// Represents an entry and its parent `HirId`.
-#[derive(Copy, Clone, Debug)]
-pub struct Entry<'hir> {
-    parent: HirId,
-    node: Node<'hir>,
-}
-
-impl<'hir> Entry<'hir> {
-    fn parent_node(self) -> Option<HirId> {
-        match self.node {
-            Node::Crate(_) => None,
-            _ => Some(self.parent),
-        }
-    }
-}
-
 fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
     match node {
         Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
@@ -86,20 +73,6 @@ fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool {
     }
 }
 
-#[derive(Debug)]
-pub(super) struct HirOwnerData<'hir> {
-    pub(super) signature: Option<&'hir Owner<'hir>>,
-    pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
-}
-
-#[derive(Debug)]
-pub struct IndexedHir<'hir> {
-    /// The SVH of the local crate.
-    pub crate_hash: Svh,
-
-    pub(super) map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
-}
-
 #[derive(Copy, Clone)]
 pub struct Map<'hir> {
     pub(super) tcx: TyCtxt<'hir>,
@@ -129,10 +102,48 @@ impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
             }
 
             self.current_id = parent_id;
-            if let Some(entry) = self.map.find_entry(parent_id) {
-                return Some((parent_id, entry.node));
+            if let Some(node) = self.map.find(parent_id) {
+                return Some((parent_id, node));
+            }
+            // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+        }
+    }
+}
+
+/// An iterator that walks up the ancestor tree of a given `HirId`.
+/// Constructed using `tcx.hir().parent_owner_iter(hir_id)`.
+pub struct ParentOwnerIterator<'map, 'hir> {
+    current_id: HirId,
+    map: &'map Map<'hir>,
+}
+
+impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> {
+    type Item = (HirId, Node<'hir>);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.current_id.local_id.index() != 0 {
+            self.current_id.local_id = ItemLocalId::new(0);
+            if let Some(node) = self.map.find(self.current_id) {
+                return Some((self.current_id, node));
+            }
+        }
+        if self.current_id == CRATE_HIR_ID {
+            return None;
+        }
+        loop {
+            // There are nodes that do not have entries, so we need to skip them.
+            let parent_id = self.map.def_key(self.current_id.owner).parent;
+
+            let parent_id = parent_id.map_or(CRATE_HIR_ID.owner, |local_def_index| {
+                let def_id = LocalDefId { local_def_index };
+                self.map.local_def_id_to_hir_id(def_id).owner
+            });
+            self.current_id = HirId::make_owner(parent_id);
+
+            // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+            if let Some(node) = self.map.find(self.current_id) {
+                return Some((self.current_id, node));
             }
-            // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`.
         }
     }
 }
@@ -165,7 +176,7 @@ impl<'hir> Map<'hir> {
             bug!(
                 "local_def_id: no entry for `{:?}`, which has a map of `{:?}`",
                 hir_id,
-                self.find_entry(hir_id)
+                self.find(hir_id)
             )
         })
     }
@@ -272,27 +283,60 @@ impl<'hir> Map<'hir> {
             .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id))
     }
 
-    fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> {
+    pub fn find_parent_node(&self, id: HirId) -> Option<HirId> {
         if id.local_id == ItemLocalId::from_u32(0) {
-            let owner = self.tcx.hir_owner(id.owner);
-            owner.map(|owner| Entry { parent: owner.parent, node: owner.node })
+            Some(self.tcx.hir_owner_parent(id.owner))
         } else {
-            let owner = self.tcx.hir_owner_nodes(id.owner);
-            owner.and_then(|owner| {
-                let node = owner.nodes[id.local_id].as_ref();
-                // FIXME(eddyb) use a single generic type instead of having both
-                // `Entry` and `ParentedNode`, which are effectively the same.
-                // Alternatively, rewrite code using `Entry` to use `ParentedNode`.
-                node.map(|node| Entry {
-                    parent: HirId { owner: id.owner, local_id: node.parent },
-                    node: node.node,
-                })
-            })
+            let owner = self.tcx.hir_owner_nodes(id.owner)?;
+            let node = owner.nodes[id.local_id].as_ref()?;
+            let hir_id = HirId { owner: id.owner, local_id: node.parent };
+            Some(hir_id)
+        }
+    }
+
+    pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
+        self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID)
+    }
+
+    /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
+    pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
+        if id.local_id == ItemLocalId::from_u32(0) {
+            let owner = self.tcx.hir_owner(id.owner)?;
+            Some(owner.node)
+        } else {
+            let owner = self.tcx.hir_owner_nodes(id.owner)?;
+            let node = owner.nodes[id.local_id].as_ref()?;
+            Some(node.node)
         }
     }
 
-    fn get_entry(&self, id: HirId) -> Entry<'hir> {
-        self.find_entry(id).unwrap()
+    /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
+    pub fn get(&self, id: HirId) -> Node<'hir> {
+        self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
+    }
+
+    pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
+        id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
+    }
+
+    pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
+        self.get_if_local(id).and_then(|node| match &node {
+            Node::ImplItem(impl_item) => Some(&impl_item.generics),
+            Node::TraitItem(trait_item) => Some(&trait_item.generics),
+            Node::Item(Item {
+                kind:
+                    ItemKind::Fn(_, generics, _)
+                    | ItemKind::TyAlias(_, generics)
+                    | ItemKind::Enum(_, generics)
+                    | ItemKind::Struct(_, generics)
+                    | ItemKind::Union(_, generics)
+                    | ItemKind::Trait(_, _, generics, ..)
+                    | ItemKind::TraitAlias(generics, _)
+                    | ItemKind::Impl(Impl { generics, .. }),
+                ..
+            }) => Some(generics),
+            _ => None,
+        })
     }
 
     pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
@@ -457,7 +501,7 @@ impl<'hir> Map<'hir> {
 
     pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
         let hir_id = self.local_def_id_to_hir_id(module);
-        match self.get_entry(hir_id).node {
+        match self.get(hir_id) {
             Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id),
             Node::Crate(item) => (&item, item.inner, hir_id),
             node => panic!("not a module: {:?}", node),
@@ -496,60 +540,18 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
-    pub fn get(&self, id: HirId) -> Node<'hir> {
-        self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
-    }
-
-    pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
-        id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
-    }
-
-    pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
-        self.get_if_local(id).and_then(|node| match &node {
-            Node::ImplItem(impl_item) => Some(&impl_item.generics),
-            Node::TraitItem(trait_item) => Some(&trait_item.generics),
-            Node::Item(Item {
-                kind:
-                    ItemKind::Fn(_, generics, _)
-                    | ItemKind::TyAlias(_, generics)
-                    | ItemKind::Enum(_, generics)
-                    | ItemKind::Struct(_, generics)
-                    | ItemKind::Union(_, generics)
-                    | ItemKind::Trait(_, _, generics, ..)
-                    | ItemKind::TraitAlias(generics, _)
-                    | ItemKind::Impl(Impl { generics, .. }),
-                ..
-            }) => Some(generics),
-            _ => None,
-        })
-    }
-
-    /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
-    pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
-        self.find_entry(hir_id).map(|entry| entry.node)
-    }
-
-    /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there
-    /// is no parent. Note that the parent may be `CRATE_HIR_ID`, which is not itself
-    /// present in the map, so passing the return value of `get_parent_node` to
-    /// `get` may in fact panic.
-    /// This function returns the immediate parent in the HIR, whereas `get_parent`
-    /// returns the enclosing item. Note that this might not be the actual parent
-    /// node in the HIR -- some kinds of nodes are not in the map and these will
-    /// never appear as the parent node. Thus, you can always walk the parent nodes
-    /// from a node to the root of the HIR (unless you get back the same ID here,
-    /// which can happen if the ID is not in the map itself or is just weird).
-    pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
-        self.get_entry(hir_id).parent_node().unwrap_or(hir_id)
-    }
-
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
     /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
     pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
         ParentHirIterator { current_id, map: self }
     }
 
+    /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
+    /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+    pub fn parent_owner_iter(&self, current_id: HirId) -> ParentOwnerIterator<'_, 'hir> {
+        ParentOwnerIterator { current_id, map: self }
+    }
+
     /// Checks if the node is left-hand side of an assignment.
     pub fn is_lhs(&self, id: HirId) -> bool {
         match self.find(self.get_parent_node(id)) {
@@ -570,7 +572,7 @@ impl<'hir> Map<'hir> {
     /// Whether `hir_id` corresponds to a `mod` or a crate.
     pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
         matches!(
-            self.get_entry(hir_id).node,
+            self.get(hir_id),
             Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
         )
     }
@@ -600,8 +602,8 @@ impl<'hir> Map<'hir> {
     pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
         let mut iter = self.parent_iter(id).peekable();
         let mut ignore_tail = false;
-        if let Some(entry) = self.find_entry(id) {
-            if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node {
+        if let Some(node) = self.find(id) {
+            if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = node {
                 // When dealing with `return` statements, we don't care about climbing only tail
                 // expressions.
                 ignore_tail = true;
@@ -638,23 +640,23 @@ impl<'hir> Map<'hir> {
     /// in the HIR which is recorded by the map and is an item, either an item
     /// in a module, trait, or impl.
     pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
-        for (hir_id, node) in self.parent_iter(hir_id) {
-            match node {
-                Node::Crate(_)
-                | Node::Item(_)
-                | Node::ForeignItem(_)
-                | Node::TraitItem(_)
-                | Node::ImplItem(_) => return hir_id,
-                _ => {}
+        for (hir_id, node) in self.parent_owner_iter(hir_id) {
+            if let Node::Crate(_)
+            | Node::Item(_)
+            | Node::ForeignItem(_)
+            | Node::TraitItem(_)
+            | Node::ImplItem(_) = node
+            {
+                return hir_id;
             }
         }
-        hir_id
+        CRATE_HIR_ID
     }
 
     /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
     /// module parent is in this map.
     pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
-        for (hir_id, node) in self.parent_iter(hir_id) {
+        for (hir_id, node) in self.parent_owner_iter(hir_id) {
             if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
                 return hir_id;
             }
@@ -728,12 +730,8 @@ impl<'hir> Map<'hir> {
 
     pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
         let parent = self.get_parent_item(hir_id);
-        if let Some(entry) = self.find_entry(parent) {
-            if let Entry {
-                node: Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }),
-                ..
-            } = entry
-            {
+        if let Some(node) = self.find(parent) {
+            if let Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node {
                 return *abi;
             }
         }
@@ -827,7 +825,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
-        let span = match self.find_entry(hir_id)?.node {
+        let span = match self.find(hir_id)? {
             Node::Param(param) => param.span,
             Node::Item(item) => match &item.kind {
                 ItemKind::Fn(sig, _, _) => sig.span,
@@ -876,7 +874,7 @@ impl<'hir> Map<'hir> {
     /// Like `hir.span()`, but includes the body of function items
     /// (instead of just the function header)
     pub fn span_with_body(&self, hir_id: HirId) -> Span {
-        match self.find_entry(hir_id).map(|entry| entry.node) {
+        match self.find(hir_id) {
             Some(Node::TraitItem(item)) => item.span,
             Some(Node::ImplItem(impl_item)) => impl_item.span,
             Some(Node::Item(item)) => item.span,
@@ -935,19 +933,78 @@ pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx Indexe
 
     let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map");
 
-    let (map, crate_hash) = {
-        let hcx = tcx.create_stable_hashing_context();
+    let hcx = tcx.create_stable_hashing_context();
+    let mut collector =
+        NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx);
+    intravisit::walk_crate(&mut collector, tcx.untracked_crate);
 
-        let mut collector =
-            NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx);
-        intravisit::walk_crate(&mut collector, tcx.untracked_crate);
+    let map = collector.finalize_and_compute_crate_hash();
+    tcx.arena.alloc(map)
+}
 
-        let crate_disambiguator = tcx.sess.local_crate_disambiguator();
-        let cmdline_args = tcx.sess.opts.dep_tracking_hash();
-        collector.finalize_and_compute_crate_hash(crate_disambiguator, &*tcx.cstore, cmdline_args)
-    };
+pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
+    let mut hir_body_nodes: Vec<_> = tcx
+        .index_hir(crate_num)
+        .map
+        .iter_enumerated()
+        .filter_map(|(def_id, hod)| {
+            let def_path_hash = tcx.definitions.def_path_hash(def_id);
+            let hash = hod.with_bodies.as_ref()?.hash;
+            Some((def_path_hash, hash))
+        })
+        .collect();
+    hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
 
-    tcx.arena.alloc(IndexedHir { crate_hash, map })
+    let node_hashes = hir_body_nodes.iter().fold(
+        Fingerprint::ZERO,
+        |combined_fingerprint, &(def_path_hash, fingerprint)| {
+            combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
+        },
+    );
+
+    let upstream_crates = upstream_crates(&*tcx.cstore);
+
+    // We hash the final, remapped names of all local source files so we
+    // don't have to include the path prefix remapping commandline args.
+    // If we included the full mapping in the SVH, we could only have
+    // reproducible builds by compiling from the same directory. So we just
+    // hash the result of the mapping instead of the mapping itself.
+    let mut source_file_names: Vec<_> = tcx
+        .sess
+        .source_map()
+        .files()
+        .iter()
+        .filter(|source_file| source_file.cnum == LOCAL_CRATE)
+        .map(|source_file| source_file.name_hash)
+        .collect();
+
+    source_file_names.sort_unstable();
+
+    let mut hcx = tcx.create_stable_hashing_context();
+    let mut stable_hasher = StableHasher::new();
+    node_hashes.hash_stable(&mut hcx, &mut stable_hasher);
+    upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
+    source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+    tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
+    tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher);
+
+    let crate_hash: Fingerprint = stable_hasher.finish();
+    Svh::new(crate_hash.to_smaller_hash())
+}
+
+fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
+    let mut upstream_crates: Vec<_> = cstore
+        .crates_untracked()
+        .iter()
+        .map(|&cnum| {
+            let name = cstore.crate_name_untracked(cnum);
+            let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
+            let hash = cstore.crate_hash_untracked(cnum);
+            (name, disambiguator, hash)
+        })
+        .collect();
+    upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
+    upstream_crates
 }
 
 fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index cf4e473d8ac..565664778e5 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -20,18 +20,26 @@ use rustc_span::DUMMY_SP;
 use std::collections::BTreeMap;
 
 #[derive(Debug)]
+struct HirOwnerData<'hir> {
+    signature: Option<&'hir Owner<'hir>>,
+    with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
+}
+
+#[derive(Debug)]
+pub struct IndexedHir<'hir> {
+    map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    parenting: FxHashMap<LocalDefId, HirId>,
+}
+
+#[derive(Debug)]
 pub struct Owner<'tcx> {
-    parent: HirId,
     node: Node<'tcx>,
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let Owner { parent, node } = self;
-        hcx.while_hashing_hir_bodies(false, |hcx| {
-            parent.hash_stable(hcx, hasher);
-            node.hash_stable(hcx, hasher);
-        });
+        let Owner { node } = self;
+        hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher));
     }
 }
 
@@ -117,9 +125,14 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.hir_crate = |tcx, _| tcx.untracked_crate;
     providers.index_hir = map::index_hir;
+    providers.crate_hash = map::crate_hash;
     providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
     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_deref();
+    providers.hir_owner_parent = |tcx, id| {
+        let index = tcx.index_hir(LOCAL_CRATE);
+        index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
+    };
     providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
     providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
     providers.fn_arg_names = |tcx, id| {
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 7024d9a3d21..93e7aeaffce 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -89,6 +89,10 @@ bitflags! {
         /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
         /// function as an entry function from Non-Secure code.
         const CMSE_NONSECURE_ENTRY      = 1 << 14;
+        /// `#[no_coverage]`: indicates that the function should be ignored by
+        /// the MIR `InstrumentCoverage` pass and not added to the coverage map
+        /// during codegen.
+        const NO_COVERAGE               = 1 << 15;
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index e22c0b40d5a..252b5fc70de 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -683,6 +683,15 @@ impl BorrowKind {
             BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow,
         }
     }
+
+    pub fn describe_mutability(&self) -> String {
+        match *self {
+            BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => {
+                "immutable".to_string()
+            }
+            BorrowKind::Mut { .. } => "mutable".to_string(),
+        }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -1340,7 +1349,7 @@ impl<O> AssertKind<O> {
     }
 
     /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
-    fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
+    pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
     where
         O: Debug,
     {
@@ -2369,6 +2378,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                             };
                             let mut struct_fmt = fmt.debug_struct(&name);
 
+                            // FIXME(project-rfc-2229#48): This should be a list of capture names/places
                             if let Some(upvars) = tcx.upvars_mentioned(def_id) {
                                 for (&var_id, place) in iter::zip(upvars.keys(), places) {
                                     let var_name = tcx.hir().name(var_id);
@@ -2388,6 +2398,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                             let name = format!("[generator@{:?}]", tcx.hir().span(hir_id));
                             let mut struct_fmt = fmt.debug_struct(&name);
 
+                            // FIXME(project-rfc-2229#48): This should be a list of capture names/places
                             if let Some(upvars) = tcx.upvars_mentioned(def_id) {
                                 for (&var_id, place) in iter::zip(upvars.keys(), places) {
                                     let var_name = tcx.hir().name(var_id);
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 92a1094bbcd..77f38e52ad2 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::base_n;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::{HirId, ItemId};
 use rustc_session::config::OptLevel;
 use rustc_span::source_map::Span;
@@ -93,7 +93,7 @@ impl<'tcx> MonoItem<'tcx> {
                 // indicator, then we'll be creating a globally shared version.
                 if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
                     || !instance.def.generates_cgu_internal_copy(tcx)
-                    || Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
+                    || Some(instance.def_id()) == entry_def_id
                 {
                     return InstantiationMode::GloballyShared { may_conflict: false };
                 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 08fa12aa371..3ffc3641b62 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -28,7 +28,7 @@ rustc_queries! {
 
     /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
     /// Avoid calling this query directly.
-    query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> {
+    query index_hir(_: CrateNum) -> &'tcx crate::hir::IndexedHir<'tcx> {
         eval_always
         no_hash
         desc { "index HIR" }
@@ -52,6 +52,15 @@ rustc_queries! {
         desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
+    /// Gives access to the HIR node's parent for the HIR owner `key`.
+    ///
+    /// This can be conveniently accessed by methods on `tcx.hir()`.
+    /// Avoid calling this query directly.
+    query hir_owner_parent(key: LocalDefId) -> hir::HirId {
+        eval_always
+        desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+    }
+
     /// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
@@ -1194,7 +1203,7 @@ rustc_queries! {
 
     /// Identifies the entry-point (e.g., the `main` function) for a given
     /// crate, returning `None` if there is no entry point (such as for library crates).
-    query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
+    query entry_fn(_: CrateNum) -> Option<(DefId, EntryFnType)> {
         desc { "looking up the entry function of a crate" }
     }
     query plugin_registrar_fn(_: CrateNum) -> Option<DefId> {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 00dec3b355f..c9b73c68209 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -670,6 +670,9 @@ pub enum ObjectSafetyViolation {
 
     /// Associated const.
     AssocConst(Symbol, Span),
+
+    /// GAT
+    GAT(Symbol, Span),
 }
 
 impl ObjectSafetyViolation {
@@ -715,6 +718,9 @@ impl ObjectSafetyViolation {
                 format!("it contains associated `const` `{}`", name).into()
             }
             ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
+            ObjectSafetyViolation::GAT(name, _) => {
+                format!("it contains the generic associated type `{}`", name).into()
+            }
         }
     }
 
@@ -773,6 +779,7 @@ impl ObjectSafetyViolation {
                 );
             }
             ObjectSafetyViolation::AssocConst(name, _)
+            | ObjectSafetyViolation::GAT(name, _)
             | ObjectSafetyViolation::Method(name, ..) => {
                 err.help(&format!("consider moving `{}` to another trait", name));
             }
@@ -786,6 +793,7 @@ impl ObjectSafetyViolation {
             ObjectSafetyViolation::SupertraitSelf(spans)
             | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
             ObjectSafetyViolation::AssocConst(_, span)
+            | ObjectSafetyViolation::GAT(_, span)
             | ObjectSafetyViolation::Method(_, _, span)
                 if *span != DUMMY_SP =>
             {
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 887a5831cd7..7790369af7f 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -151,6 +151,10 @@ pub struct CapturedPlace<'tcx> {
 }
 
 impl CapturedPlace<'tcx> {
+    pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
+        place_to_string_for_capture(tcx, &self.place)
+    }
+
     /// Returns the hir-id of the root variable for the captured place.
     /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
     pub fn get_root_variable(&self) -> hir::HirId {
@@ -168,6 +172,22 @@ impl CapturedPlace<'tcx> {
         }
     }
 
+    /// Return span pointing to use that resulted in selecting the captured path
+    pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span {
+        if let Some(path_expr_id) = self.info.path_expr_id {
+            tcx.hir().span(path_expr_id)
+        } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
+            tcx.hir().span(capture_kind_expr_id)
+        } else {
+            // Fallback on upvars mentioned if neither path or capture expr id is captured
+
+            // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
+            tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
+                [&self.get_root_variable()]
+                .span
+        }
+    }
+
     /// Return span pointing to use that resulted in selecting the current capture kind
     pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
         if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index bb2b00cbaea..b414618f7d5 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -20,8 +20,8 @@ use crate::ty::TyKind::*;
 use crate::ty::{
     self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
     DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
-    InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate,
-    PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
+    InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig,
+    Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
     TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
 };
 use rustc_ast as ast;
@@ -1025,6 +1025,8 @@ pub struct GlobalCtxt<'tcx> {
     layout_interner: ShardedHashMap<&'tcx Layout, ()>,
 
     output_filenames: Arc<OutputFilenames>,
+
+    pub main_def: Option<MainDefinition>,
 }
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -1185,6 +1187,7 @@ impl<'tcx> TyCtxt<'tcx> {
             const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
             output_filenames: Arc::new(output_filenames.clone()),
+            main_def: resolutions.main_def,
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 01bc5cc761c..92288c89827 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -59,6 +59,10 @@ impl FlagComputation {
     {
         let mut computation = FlagComputation::new();
 
+        if !value.bound_vars().is_empty() {
+            computation.flags = computation.flags | TypeFlags::HAS_RE_LATE_BOUND;
+        }
+
         f(&mut computation, value.skip_binder());
 
         self.add_flags(computation.flags);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6574c938260..af49533753f 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -124,6 +124,20 @@ pub struct ResolverOutputs {
     /// Extern prelude entries. The value is `true` if the entry was introduced
     /// via `extern crate` item and not `--extern` option or compiler built-in.
     pub extern_prelude: FxHashMap<Symbol, bool>,
+    pub main_def: Option<MainDefinition>,
+}
+
+#[derive(Clone, Copy)]
+pub struct MainDefinition {
+    pub res: Res<ast::NodeId>,
+    pub is_import: bool,
+    pub span: Span,
+}
+
+impl MainDefinition {
+    pub fn opt_fn_def_id(self) -> Option<DefId> {
+        if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None }
+    }
 }
 
 /// The "header" of an impl is everything outside the body: a Self type, a trait
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index c170858ba85..81230e32f56 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -1,6 +1,5 @@
 use crate::dep_graph;
 use crate::hir::exports::Export;
-use crate::hir::map;
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintLevelMap;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
index 416199b3840..43b775f8083 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -1185,20 +1185,27 @@ where
 
     assert!(Q::query_state(tcx).all_inactive());
     let cache = Q::query_cache(tcx);
-    cache.iter_results(|results| {
-        for (key, value, dep_node) in results {
-            if Q::cache_on_disk(tcx, &key, Some(value)) {
-                let dep_node = SerializedDepNodeIndex::new(dep_node.index());
-
-                // Record position of the cache entry.
-                query_result_index
-                    .push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
-
-                // Encode the type check tables with the `SerializedDepNodeIndex`
-                // as tag.
-                encoder.encode_tagged(dep_node, value)?;
+    let mut res = Ok(());
+    cache.iter_results(&mut |key, value, dep_node| {
+        if res.is_err() {
+            return;
+        }
+        if Q::cache_on_disk(tcx, &key, Some(value)) {
+            let dep_node = SerializedDepNodeIndex::new(dep_node.index());
+
+            // Record position of the cache entry.
+            query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
+
+            // Encode the type check tables with the `SerializedDepNodeIndex`
+            // as tag.
+            match encoder.encode_tagged(dep_node, value) {
+                Ok(()) => {}
+                Err(e) => {
+                    res = Err(e);
+                }
             }
         }
-        Ok(())
-    })
+    });
+
+    res
 }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index 9f19a474ca3..30e0b293ffb 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -99,7 +99,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
             err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
 
-            use_spans.var_span_label(
+            use_spans.var_span_label_path_only(
                 &mut err,
                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
             );
@@ -255,6 +255,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 partially_str,
                                 move_spans.describe()
                             ),
+                            "moved",
                         );
                     }
                 }
@@ -304,7 +305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
             }
 
-            use_spans.var_span_label(
+            use_spans.var_span_label_path_only(
                 &mut err,
                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
             );
@@ -434,13 +435,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
         err.span_label(span, format!("move out of {} occurs here", value_msg));
 
-        borrow_spans.var_span_label(
+        borrow_spans.var_span_label_path_only(
             &mut err,
             format!("borrow occurs due to use{}", borrow_spans.describe()),
         );
 
-        move_spans
-            .var_span_label(&mut err, format!("move occurs due to use{}", move_spans.describe()));
+        move_spans.var_span_label(
+            &mut err,
+            format!("move occurs due to use{}", move_spans.describe()),
+            "moved",
+        );
 
         self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(
@@ -468,6 +472,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let use_spans = self.move_spans(place.as_ref(), location);
         let span = use_spans.var_or_use();
 
+        // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use
+        // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
         let mut err = self.cannot_use_when_mutably_borrowed(
             span,
             &self.describe_any_place(place.as_ref()),
@@ -475,11 +481,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             &self.describe_any_place(borrow.borrowed_place.as_ref()),
         );
 
-        borrow_spans.var_span_label(&mut err, {
-            let place = &borrow.borrowed_place;
-            let desc_place = self.describe_any_place(place.as_ref());
-            format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
-        });
+        borrow_spans.var_span_label(
+            &mut err,
+            {
+                let place = &borrow.borrowed_place;
+                let desc_place = self.describe_any_place(place.as_ref());
+                format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
+            },
+            "mutable",
+        );
 
         self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(
@@ -591,6 +601,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             desc_place,
                             borrow_spans.describe(),
                         ),
+                        "immutable",
                     );
 
                     return err;
@@ -667,7 +678,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if issued_spans == borrow_spans {
             borrow_spans.var_span_label(
                 &mut err,
-                format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe()),
+                format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
+                gen_borrow_kind.describe_mutability(),
             );
         } else {
             let borrow_place = &issued_borrow.borrowed_place;
@@ -679,6 +691,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     borrow_place_desc,
                     issued_spans.describe(),
                 ),
+                issued_borrow.kind.describe_mutability(),
             );
 
             borrow_spans.var_span_label(
@@ -688,6 +701,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     desc_place,
                     borrow_spans.describe(),
                 ),
+                gen_borrow_kind.describe_mutability(),
             );
         }
 
@@ -847,7 +861,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
 
         let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.var_or_use();
+        let borrow_span = borrow_spans.var_or_use_path_span();
 
         assert!(root_place.projection.is_empty());
         let proper_span = self.body.local_decls[root_place.local].source_info.span;
@@ -987,7 +1001,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             location, name, borrow, drop_span, borrow_spans
         );
 
-        let borrow_span = borrow_spans.var_or_use();
+        let borrow_span = borrow_spans.var_or_use_path_span();
         if let BorrowExplanation::MustBeValidFor {
             category,
             span,
@@ -1575,6 +1589,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 loan_spans.var_span_label(
                     &mut err,
                     format!("borrow occurs due to use{}", loan_spans.describe()),
+                    loan.kind.describe_mutability(),
                 );
 
                 err.buffer(&mut self.errors_buffer);
@@ -1585,8 +1600,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
 
-        loan_spans
-            .var_span_label(&mut err, format!("borrow occurs due to use{}", loan_spans.describe()));
+        loan_spans.var_span_label(
+            &mut err,
+            format!("borrow occurs due to use{}", loan_spans.describe()),
+            loan.kind.describe_mutability(),
+        );
 
         self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
             self.infcx.tcx,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
index 2a388b8a72b..1b0cae51d58 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
@@ -24,8 +24,8 @@ use super::{find_use, RegionName, UseSpans};
 
 #[derive(Debug)]
 pub(in crate::borrow_check) enum BorrowExplanation {
-    UsedLater(LaterUseKind, Span),
-    UsedLaterInLoop(LaterUseKind, Span),
+    UsedLater(LaterUseKind, Span, Option<Span>),
+    UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
     UsedLaterWhenDropped {
         drop_loc: Location,
         dropped_local: Local,
@@ -67,7 +67,7 @@ impl BorrowExplanation {
         borrow_span: Option<Span>,
     ) {
         match *self {
-            BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
+            BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
                 let message = match later_use_kind {
                     LaterUseKind::TraitCapture => "captured here by trait object",
                     LaterUseKind::ClosureCapture => "captured here by closure",
@@ -75,14 +75,31 @@ impl BorrowExplanation {
                     LaterUseKind::FakeLetRead => "stored here",
                     LaterUseKind::Other => "used here",
                 };
-                if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
-                    err.span_label(
-                        var_or_use_span,
-                        format!("{}borrow later {}", borrow_desc, message),
-                    );
+                // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
+                if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
+                    if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
+                        err.span_label(
+                            var_or_use_span,
+                            format!("{}borrow later {}", borrow_desc, message),
+                        );
+                    }
+                } else {
+                    // path_span must be `Some` as otherwise the if condition is true
+                    let path_span = path_span.unwrap();
+                    // path_span is only present in the case of closure capture
+                    assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+                    if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
+                        let path_label = "used here by closure";
+                        let capture_kind_label = message;
+                        err.span_label(
+                            var_or_use_span,
+                            format!("{}borrow later {}", borrow_desc, capture_kind_label),
+                        );
+                        err.span_label(path_span, path_label);
+                    }
                 }
             }
-            BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
+            BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => {
                 let message = match later_use_kind {
                     LaterUseKind::TraitCapture => {
                         "borrow captured here by trait object, in later iteration of loop"
@@ -94,7 +111,24 @@ impl BorrowExplanation {
                     LaterUseKind::FakeLetRead => "borrow later stored here",
                     LaterUseKind::Other => "borrow used here, in later iteration of loop",
                 };
-                err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+                // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
+                if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
+                    err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+                } else {
+                    // path_span must be `Some` as otherwise the if condition is true
+                    let path_span = path_span.unwrap();
+                    // path_span is only present in the case of closure capture
+                    assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+                    if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
+                        let path_label = "used here by closure";
+                        let capture_kind_label = message;
+                        err.span_label(
+                            var_or_use_span,
+                            format!("{}borrow later {}", borrow_desc, capture_kind_label),
+                        );
+                        err.span_label(path_span, path_label);
+                    }
+                }
             }
             BorrowExplanation::UsedLaterWhenDropped {
                 drop_loc,
@@ -311,13 +345,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let borrow_location = location;
                 if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
                     let later_use = self.later_use_kind(borrow, spans, location);
-                    BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
+                    BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
                 } else {
                     // Check if the location represents a `FakeRead`, and adapt the error
                     // message to the `FakeReadCause` it is from: in particular,
                     // the ones inserted in optimized `let var = <expr>` patterns.
                     let later_use = self.later_use_kind(borrow, spans, location);
-                    BorrowExplanation::UsedLater(later_use.0, later_use.1)
+                    BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2)
                 }
             }
 
@@ -498,16 +532,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     /// Determine how the borrow was later used.
+    /// First span returned points to the location of the conflicting use
+    /// Second span if `Some` is returned in the case of closures and points
+    /// to the use of the path
     fn later_use_kind(
         &self,
         borrow: &BorrowData<'tcx>,
         use_spans: UseSpans<'tcx>,
         location: Location,
-    ) -> (LaterUseKind, Span) {
+    ) -> (LaterUseKind, Span, Option<Span>) {
         match use_spans {
-            UseSpans::ClosureUse { var_span, .. } => {
+            UseSpans::ClosureUse { capture_kind_span, path_span, .. } => {
                 // Used in a closure.
-                (LaterUseKind::ClosureCapture, var_span)
+                (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span))
             }
             UseSpans::PatUse(span)
             | UseSpans::OtherUse(span)
@@ -542,7 +579,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 }
                             }
                         };
-                        return (LaterUseKind::Call, function_span);
+                        return (LaterUseKind::Call, function_span, None);
                     } else {
                         LaterUseKind::Other
                     }
@@ -550,7 +587,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     LaterUseKind::Other
                 };
 
-                (kind, span)
+                (kind, span, None)
             }
         }
     }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index aa9f18d9996..1bb8c7ebe5a 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -18,7 +18,6 @@ use rustc_span::{
     Span,
 };
 use rustc_target::abi::VariantIdx;
-use std::iter;
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
@@ -216,11 +215,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             PlaceRef { local, projection: [proj_base @ .., elem] } => {
                 match elem {
                     ProjectionElem::Deref => {
-                        // FIXME(project-rfc_2229#36): print capture precisely here.
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
                             let var_index = field.index();
-                            let name = self.upvars[var_index].name.to_string();
+                            let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
                             if self.upvars[var_index].by_ref {
                                 buf.push_str(&name);
                             } else {
@@ -265,7 +263,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
                             let var_index = field.index();
-                            let name = self.upvars[var_index].name.to_string();
+                            let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
                             buf.push_str(&name);
                         } else {
                             let field_name = self
@@ -550,8 +548,12 @@ pub(super) enum UseSpans<'tcx> {
         /// The span of the args of the closure, including the `move` keyword if
         /// it's present.
         args_span: Span,
-        /// The span of the first use of the captured variable inside the closure.
-        var_span: Span,
+        /// The span of the use resulting in capture kind
+        /// Check `ty::CaptureInfo` for more details
+        capture_kind_span: Span,
+        /// The span of the use resulting in the captured path
+        /// Check `ty::CaptureInfo` for more details
+        path_span: Span,
     },
     /// The access is caused by using a variable as the receiver of a method
     /// that takes 'self'
@@ -606,9 +608,23 @@ impl UseSpans<'_> {
         }
     }
 
+    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
+    pub(super) fn var_or_use_path_span(self) -> Span {
+        match self {
+            UseSpans::ClosureUse { path_span: span, .. }
+            | UseSpans::PatUse(span)
+            | UseSpans::OtherUse(span) => span,
+            UseSpans::FnSelfUse {
+                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+            } => fn_call_span,
+            UseSpans::FnSelfUse { var_span, .. } => var_span,
+        }
+    }
+
+    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
     pub(super) fn var_or_use(self) -> Span {
         match self {
-            UseSpans::ClosureUse { var_span: span, .. }
+            UseSpans::ClosureUse { capture_kind_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
             UseSpans::FnSelfUse {
@@ -637,13 +653,34 @@ impl UseSpans<'_> {
     }
 
     // Add a span label to the use of the captured variable, if it exists.
+    // only adds label to the `path_span`
+    pub(super) fn var_span_label_path_only(
+        self,
+        err: &mut DiagnosticBuilder<'_>,
+        message: impl Into<String>,
+    ) {
+        if let UseSpans::ClosureUse { path_span, .. } = self {
+            err.span_label(path_span, message);
+        }
+    }
+
+    // Add a span label to the use of the captured variable, if it exists.
     pub(super) fn var_span_label(
         self,
         err: &mut DiagnosticBuilder<'_>,
         message: impl Into<String>,
+        kind_desc: impl Into<String>,
     ) {
-        if let UseSpans::ClosureUse { var_span, .. } = self {
-            err.span_label(var_span, message);
+        if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
+            if capture_kind_span == path_span {
+                err.span_label(capture_kind_span, message);
+            } else {
+                let capture_kind_label =
+                    format!("capture is {} because of use here", kind_desc.into());
+                let path_label = message;
+                err.span_label(capture_kind_span, capture_kind_label);
+                err.span_label(path_span, path_label);
+            }
         }
     }
 
@@ -791,10 +828,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 box AggregateKind::Closure(def_id, _)
                 | box AggregateKind::Generator(def_id, _, _) => {
                     debug!("move_spans: def_id={:?} places={:?}", def_id, places);
-                    if let Some((args_span, generator_kind, var_span)) =
+                    if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                         self.closure_span(*def_id, moved_place, places)
                     {
-                        return ClosureUse { generator_kind, args_span, var_span };
+                        return ClosureUse {
+                            generator_kind,
+                            args_span,
+                            capture_kind_span,
+                            path_span,
+                        };
                     }
                 }
                 _ => {}
@@ -809,10 +851,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 | FakeReadCause::ForLet(Some(closure_def_id)) => {
                     debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
                     let places = &[Operand::Move(*place)];
-                    if let Some((args_span, generator_kind, var_span)) =
+                    if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                         self.closure_span(closure_def_id, moved_place, places)
                     {
-                        return ClosureUse { generator_kind, args_span, var_span };
+                        return ClosureUse {
+                            generator_kind,
+                            args_span,
+                            capture_kind_span,
+                            path_span,
+                        };
                     }
                 }
                 _ => {}
@@ -972,10 +1019,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
                     def_id, is_generator, places
                 );
-                if let Some((args_span, generator_kind, var_span)) =
+                if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                     self.closure_span(*def_id, Place::from(target).as_ref(), places)
                 {
-                    return ClosureUse { generator_kind, args_span, var_span };
+                    return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
                 } else {
                     return OtherUse(use_span);
                 }
@@ -989,13 +1036,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         OtherUse(use_span)
     }
 
-    /// Finds the span of a captured variable within a closure or generator.
+    /// Finds the spans of a captured place within a closure or generator.
+    /// The first span is the location of the use resulting in the capture kind of the capture
+    /// The second span is the location the use resulting in the captured path of the capture
     fn closure_span(
         &self,
         def_id: DefId,
         target_place: PlaceRef<'tcx>,
         places: &[Operand<'tcx>],
-    ) -> Option<(Span, Option<GeneratorKind>, Span)> {
+    ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
         debug!(
             "closure_span: def_id={:?} target_place={:?} places={:?}",
             def_id, target_place, places
@@ -1005,13 +1054,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
         if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
-            for (captured_place, place) in iter::zip(
-                self.infcx.tcx.typeck(def_id.expect_local()).closure_min_captures_flattened(def_id),
-                places,
-            ) {
-                let upvar_hir_id = captured_place.get_root_variable();
-                //FIXME(project-rfc-2229#8): Use better span from captured_place
-                let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span;
+            for (captured_place, place) in self
+                .infcx
+                .tcx
+                .typeck(def_id.expect_local())
+                .closure_min_captures_flattened(def_id)
+                .zip(places)
+            {
                 match place {
                     Operand::Copy(place) | Operand::Move(place)
                         if target_place == place.as_ref() =>
@@ -1020,18 +1069,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         let body = self.infcx.tcx.hir().body(*body_id);
                         let generator_kind = body.generator_kind();
 
-                        // If we have a more specific span available, point to that.
-                        // We do this even though this span might be part of a borrow error
-                        // message rather than a move error message. Our goal is to point
-                        // to a span that shows why the upvar is used in the closure,
-                        // so a move-related span is as good as any (and potentially better,
-                        // if the overall error is due to a move of the upvar).
-
-                        let usage_span = match captured_place.info.capture_kind {
-                            ty::UpvarCapture::ByValue(Some(span)) => span,
-                            _ => span,
-                        };
-                        return Some((*args_span, generator_kind, usage_span));
+                        return Some((
+                            *args_span,
+                            generator_kind,
+                            captured_place.get_capture_kind_span(self.infcx.tcx),
+                            captured_place.get_path_span(self.infcx.tcx),
+                        ));
                     }
                     _ => {}
                 }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
index fb7694b7d88..3f87d9c7ac9 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
@@ -345,10 +345,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 };
 
                 let upvar = &self.upvars[upvar_field.unwrap().index()];
-                // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise
-                //                            capture.
                 let upvar_hir_id = upvar.place.get_root_variable();
-                let upvar_name = upvar.name;
+                let upvar_name = upvar.place.to_string(self.infcx.tcx);
                 let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
 
                 let place_name = self.describe_any_place(move_place.as_ref());
@@ -478,8 +476,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
 
                 use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
-                use_spans
-                    .var_span_label(err, format!("move occurs due to use{}", use_spans.describe()));
+                use_spans.var_span_label(
+                    err,
+                    format!("move occurs due to use{}", use_spans.describe()),
+                    "moved",
+                );
             }
         }
     }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 28f6508cab2..88122777d2e 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -85,7 +85,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
                         reason = ", as it is not declared as mutable".to_string();
                     } else {
-                        let name = self.upvars[upvar_index.index()].name;
+                        let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx);
                         reason = format!(", as `{}` is not declared as mutable", name);
                     }
                 }
@@ -195,6 +195,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         "mutable borrow occurs due to use of {} in closure",
                         self.describe_any_place(access_place.as_ref()),
                     ),
+                    "mutable",
                 );
                 borrow_span
             }
@@ -642,15 +643,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                         .starts_with(&original_method_ident.name.to_string())
                             })
                             .map(|ident| format!("{}()", ident))
+                            .peekable()
                     });
 
-                if let Some(suggestions) = opt_suggestions {
-                    err.span_suggestions(
-                        path_segment.ident.span,
-                        &format!("use mutable method"),
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
+                if let Some(mut suggestions) = opt_suggestions {
+                    if suggestions.peek().is_some() {
+                        err.span_suggestions(
+                            path_segment.ident.span,
+                            &format!("use mutable method"),
+                            suggestions,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
             }
         };
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
index 058986593a4..8665ef06126 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
@@ -385,6 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
         diag.span_label(*span, message);
 
+        // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id
         if let ReturnConstraint::ClosureUpvar(upvar) = kind {
             let def_id = match self.regioncx.universal_regions().defining_ty {
                 DefiningTy::Closure(def_id, _) => def_id,
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 2d1d83b1655..4c35be39a3d 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -74,9 +74,6 @@ crate use region_infer::RegionInferenceContext;
 // FIXME(eddyb) perhaps move this somewhere more centrally.
 #[derive(Debug)]
 crate struct Upvar<'tcx> {
-    // FIXME(project-rfc_2229#36): print capture precisely here.
-    name: Symbol,
-
     place: CapturedPlace<'tcx>,
 
     /// If true, the capture is behind a reference.
@@ -159,13 +156,12 @@ fn do_mir_borrowck<'a, 'tcx>(
     let upvars: Vec<_> = tables
         .closure_min_captures_flattened(def.did.to_def_id())
         .map(|captured_place| {
-            let var_hir_id = captured_place.get_root_variable();
             let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
                 ty::UpvarCapture::ByValue(_) => false,
                 ty::UpvarCapture::ByRef(..) => true,
             };
-            Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref }
+            Upvar { place: captured_place.clone(), by_ref }
         })
         .collect();
 
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index 3248554e204..d27fcb2f26f 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -97,7 +97,7 @@ mod relate_tys;
 
 /// Type checks the given `mir` in the context of the inference
 /// context `infcx`. Returns any region constraints that have yet to
-/// be proven. This result is includes liveness constraints that
+/// be proven. This result includes liveness constraints that
 /// ensure that regions appearing in the types of all local variables
 /// are live at all points where that local variable may later be
 /// used.
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index e621bc9167d..fdefc890674 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -1066,7 +1066,7 @@ struct RootCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     mode: MonoItemCollectionMode,
     output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
-    entry_fn: Option<(LocalDefId, EntryFnType)>,
+    entry_fn: Option<(DefId, EntryFnType)>,
 }
 
 impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
@@ -1154,7 +1154,7 @@ impl RootCollector<'_, 'v> {
             && match self.mode {
                 MonoItemCollectionMode::Eager => true,
                 MonoItemCollectionMode::Lazy => {
-                    self.entry_fn.map(|(id, _)| id) == Some(def_id)
+                    self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id)
                         || self.tcx.is_reachable_non_generic(def_id)
                         || self
                             .tcx
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index cf7d404a077..63fc66f2b9f 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -426,7 +426,7 @@ impl Validator<'mir, 'tcx> {
                     ty::PredicateKind::Subtype(_) => {
                         bug!("subtype predicate on function: {:#?}", predicate)
                     }
-                    ty::PredicateKind::Trait(pred, constness) => {
+                    ty::PredicateKind::Trait(pred, _constness) => {
                         if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                             continue;
                         }
@@ -440,16 +440,7 @@ impl Validator<'mir, 'tcx> {
                                 // arguments when determining importance.
                                 let kind = LocalKind::Arg;
 
-                                if constness == hir::Constness::Const {
-                                    self.check_op_spanned(ops::ty::TraitBound(kind), span);
-                                } else if !tcx.features().const_fn
-                                    || self.ccx.is_const_stable_const_fn()
-                                {
-                                    // HACK: We shouldn't need the conditional above, but trait
-                                    // bounds on containing impl blocks are wrongly being marked as
-                                    // "not-const".
-                                    self.check_op_spanned(ops::ty::TraitBound(kind), span);
-                                }
+                                self.check_op_spanned(ops::ty::TraitBound(kind), span);
                             }
                             // other kinds of bounds are either tautologies
                             // or cause errors in other passes
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs
index 3ef03ec21ad..eaeb44289cf 100644
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ b/compiler/rustc_mir/src/transform/coverage/mod.rs
@@ -23,6 +23,7 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::hir;
 use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::ich::StableHashingContext;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::{
     self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
@@ -87,6 +88,11 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
             _ => {}
         }
 
+        let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id());
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+            return;
+        }
+
         trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());
         Instrumentor::new(&self.name(), tcx, mir_body).inject_counters();
         trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs
index 249f5e835cd..b3fc2a0cb5e 100644
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ b/compiler/rustc_mir/src/transform/coverage/spans.rs
@@ -11,8 +11,9 @@ use rustc_middle::mir::{
 use rustc_middle::ty::TyCtxt;
 
 use rustc_span::source_map::original_sp;
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
 
+use std::cell::RefCell;
 use std::cmp::Ordering;
 
 #[derive(Debug, Copy, Clone)]
@@ -67,6 +68,8 @@ impl CoverageStatement {
 #[derive(Debug, Clone)]
 pub(super) struct CoverageSpan {
     pub span: Span,
+    pub expn_span: Span,
+    pub current_macro_or_none: RefCell<Option<Option<Symbol>>>,
     pub bcb: BasicCoverageBlock,
     pub coverage_statements: Vec<CoverageStatement>,
     pub is_closure: bool,
@@ -74,12 +77,20 @@ pub(super) struct CoverageSpan {
 
 impl CoverageSpan {
     pub fn for_fn_sig(fn_sig_span: Span) -> Self {
-        Self { span: fn_sig_span, bcb: START_BCB, coverage_statements: vec![], is_closure: false }
+        Self {
+            span: fn_sig_span,
+            expn_span: fn_sig_span,
+            current_macro_or_none: Default::default(),
+            bcb: START_BCB,
+            coverage_statements: vec![],
+            is_closure: false,
+        }
     }
 
     pub fn for_statement(
         statement: &Statement<'tcx>,
         span: Span,
+        expn_span: Span,
         bcb: BasicCoverageBlock,
         bb: BasicBlock,
         stmt_index: usize,
@@ -94,15 +105,24 @@ impl CoverageSpan {
 
         Self {
             span,
+            expn_span,
+            current_macro_or_none: Default::default(),
             bcb,
             coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
             is_closure,
         }
     }
 
-    pub fn for_terminator(span: Span, bcb: BasicCoverageBlock, bb: BasicBlock) -> Self {
+    pub fn for_terminator(
+        span: Span,
+        expn_span: Span,
+        bcb: BasicCoverageBlock,
+        bb: BasicBlock,
+    ) -> Self {
         Self {
             span,
+            expn_span,
+            current_macro_or_none: Default::default(),
             bcb,
             coverage_statements: vec![CoverageStatement::Terminator(bb, span)],
             is_closure: false,
@@ -158,6 +178,38 @@ impl CoverageSpan {
             .collect::<Vec<_>>()
             .join("\n")
     }
+
+    /// If the span is part of a macro, returns the macro name symbol.
+    pub fn current_macro(&self) -> Option<Symbol> {
+        self.current_macro_or_none
+            .borrow_mut()
+            .get_or_insert_with(|| {
+                if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
+                    self.expn_span.ctxt().outer_expn_data().kind
+                {
+                    return Some(current_macro);
+                }
+                None
+            })
+            .map(|symbol| symbol)
+    }
+
+    /// If the span is part of a macro, and the macro is visible (expands directly to the given
+    /// body_span), returns the macro name symbol.
+    pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
+        if let Some(current_macro) = self.current_macro() {
+            if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt()
+                == body_span.ctxt()
+            {
+                return Some(current_macro);
+            }
+        }
+        None
+    }
+
+    pub fn is_macro_expansion(&self) -> bool {
+        self.current_macro().is_some()
+    }
 }
 
 /// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a
@@ -191,16 +243,23 @@ pub struct CoverageSpans<'a, 'tcx> {
     /// iteration.
     some_curr: Option<CoverageSpan>,
 
-    /// The original `span` for `curr`, in case the `curr` span is modified.
+    /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span`
+    /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()`
+    /// is mutated.
     curr_original_span: Span,
 
     /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`.
     /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
     some_prev: Option<CoverageSpan>,
 
-    /// Assigned from `curr_original_span` from the previous iteration.
+    /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span`
+    /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()`
+    /// is mutated.
     prev_original_span: Span,
 
+    /// A copy of the expn_span from the prior iteration.
+    prev_expn_span: Option<Span>,
+
     /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
     /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
     /// If a new `curr` span also fits this criteria (compared to an existing list of
@@ -255,15 +314,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
             curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
             some_prev: None,
             prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
+            prev_expn_span: None,
             pending_dups: Vec::new(),
         };
 
         let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans();
 
         coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter());
-        coverage_spans.some_prev = coverage_spans.sorted_spans_iter.as_mut().unwrap().next();
-        coverage_spans.prev_original_span =
-            coverage_spans.some_prev.as_ref().expect("at least one span").span;
 
         coverage_spans.to_refined_spans()
     }
@@ -317,10 +374,14 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
     /// de-duplicated `CoverageSpan`s.
     fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
         while self.next_coverage_span() {
-            if self.curr().is_mergeable(self.prev()) {
+            if self.some_prev.is_none() {
+                debug!("  initial span");
+                self.check_invoked_macro_name_span();
+            } else if self.curr().is_mergeable(self.prev()) {
                 debug!("  same bcb (and neither is a closure), merge with prev={:?}", self.prev());
                 let prev = self.take_prev();
                 self.curr_mut().merge_from(prev);
+                self.check_invoked_macro_name_span();
             // Note that curr.span may now differ from curr_original_span
             } else if self.prev_ends_before_curr() {
                 debug!(
@@ -329,7 +390,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
                     self.prev()
                 );
                 let prev = self.take_prev();
-                self.refined_spans.push(prev);
+                self.push_refined_span(prev);
+                self.check_invoked_macro_name_span();
             } else if self.prev().is_closure {
                 // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
                 // next iter
@@ -342,20 +404,45 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
             } else if self.curr().is_closure {
                 self.carve_out_span_for_closure();
             } else if self.prev_original_span == self.curr().span {
-                // Note that this compares the new span to `prev_original_span`, which may not
-                // be the full `prev.span` (if merged during the previous iteration).
-                self.hold_pending_dups_unless_dominated();
+                // Note that this compares the new (`curr`) span to `prev_original_span`.
+                // In this branch, the actual span byte range of `prev_original_span` is not
+                // important. What is important is knowing whether the new `curr` span was
+                // **originally** the same as the original span of `prev()`. The original spans
+                // reflect their original sort order, and for equal spans, conveys a partial
+                // ordering based on CFG dominator priority.
+                if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() {
+                    // Macros that expand to include branching (such as
+                    // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
+                    // `trace!()) typically generate callee spans with identical
+                    // ranges (typically the full span of the macro) for all
+                    // `BasicBlocks`. This makes it impossible to distinguish
+                    // the condition (`if val1 != val2`) from the optional
+                    // branched statements (such as the call to `panic!()` on
+                    // assert failure). In this case it is better (or less
+                    // worse) to drop the optional branch bcbs and keep the
+                    // non-conditional statements, to count when reached.
+                    debug!(
+                        "  curr and prev are part of a macro expansion, and curr has the same span \
+                        as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
+                        prev={:?}",
+                        self.prev()
+                    );
+                    self.take_curr();
+                } else {
+                    self.hold_pending_dups_unless_dominated();
+                }
             } else {
                 self.cutoff_prev_at_overlapping_curr();
+                self.check_invoked_macro_name_span();
             }
         }
 
         debug!("    AT END, adding last prev={:?}", self.prev());
         let prev = self.take_prev();
-        let CoverageSpans { pending_dups, mut refined_spans, .. } = self;
+        let pending_dups = self.pending_dups.split_off(0);
         for dup in pending_dups {
             debug!("    ...adding at least one pending dup={:?}", dup);
-            refined_spans.push(dup);
+            self.push_refined_span(dup);
         }
 
         // Async functions wrap a closure that implements the body to be executed. The enclosing
@@ -365,21 +452,60 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
         // excluded. The closure's `Return` is the only one that will be counted. This provides
         // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
         // of the function body.)
-        let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() {
+        let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() {
             last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
         } else {
             false
         };
 
         if !body_ends_with_closure {
-            refined_spans.push(prev);
+            self.push_refined_span(prev);
         }
 
         // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
         // regions for the current function leave room for the closure's own coverage regions
         // (injected separately, from the closure's own MIR).
-        refined_spans.retain(|covspan| !covspan.is_closure);
-        refined_spans
+        self.refined_spans.retain(|covspan| !covspan.is_closure);
+        self.refined_spans
+    }
+
+    fn push_refined_span(&mut self, covspan: CoverageSpan) {
+        let len = self.refined_spans.len();
+        if len > 0 {
+            let last = &mut self.refined_spans[len - 1];
+            if last.is_mergeable(&covspan) {
+                debug!(
+                    "merging new refined span with last refined span, last={:?}, covspan={:?}",
+                    last, covspan
+                );
+                last.merge_from(covspan);
+                return;
+            }
+        }
+        self.refined_spans.push(covspan)
+    }
+
+    fn check_invoked_macro_name_span(&mut self) {
+        if let Some(visible_macro) = self.curr().visible_macro(self.body_span) {
+            if self.prev_expn_span.map_or(true, |prev_expn_span| {
+                self.curr().expn_span.ctxt() != prev_expn_span.ctxt()
+            }) {
+                let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo();
+                let after_macro_bang =
+                    merged_prefix_len + BytePos(visible_macro.as_str().bytes().count() as u32 + 1);
+                let mut macro_name_cov = self.curr().clone();
+                self.curr_mut().span =
+                    self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang);
+                macro_name_cov.span =
+                    macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
+                debug!(
+                    "  and curr starts a new macro expansion, so add a new span just for \
+                            the macro `{}!`, new span={:?}",
+                    visible_macro, macro_name_cov
+                );
+                self.push_refined_span(macro_name_cov);
+            }
+        }
     }
 
     // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
@@ -401,14 +527,17 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
                     .iter()
                     .enumerate()
                     .filter_map(move |(index, statement)| {
-                        filtered_statement_span(statement, self.body_span).map(|span| {
-                            CoverageSpan::for_statement(statement, span, bcb, bb, index)
-                        })
+                        filtered_statement_span(statement, self.body_span).map(
+                            |(span, expn_span)| {
+                                CoverageSpan::for_statement(
+                                    statement, span, expn_span, bcb, bb, index,
+                                )
+                            },
+                        )
                     })
-                    .chain(
-                        filtered_terminator_span(data.terminator(), self.body_span)
-                            .map(|span| CoverageSpan::for_terminator(span, bcb, bb)),
-                    )
+                    .chain(filtered_terminator_span(data.terminator(), self.body_span).map(
+                        |(span, expn_span)| CoverageSpan::for_terminator(span, expn_span, bcb, bb),
+                    ))
             })
             .collect()
     }
@@ -461,7 +590,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
                     let pending_dups = self.pending_dups.split_off(0);
                     for dup in pending_dups.into_iter() {
                         debug!("    ...adding at least one pending={:?}", dup);
-                        self.refined_spans.push(dup);
+                        self.push_refined_span(dup);
                     }
                 } else {
                     self.pending_dups.clear();
@@ -473,12 +602,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
     /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
     fn next_coverage_span(&mut self) -> bool {
         if let Some(curr) = self.some_curr.take() {
+            self.prev_expn_span = Some(curr.expn_span);
             self.some_prev = Some(curr);
             self.prev_original_span = self.curr_original_span;
         }
         while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() {
             debug!("FOR curr={:?}", curr);
-            if self.prev_starts_after_next(&curr) {
+            if self.some_prev.is_some() && self.prev_starts_after_next(&curr) {
                 debug!(
                     "  prev.span starts after curr.span, so curr will be dropped (skipping past \
                     closure?); prev={:?}",
@@ -535,29 +665,38 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
                 for mut dup in pending_dups.iter().cloned() {
                     dup.span = dup.span.with_hi(left_cutoff);
                     debug!("    ...and at least one pre_closure dup={:?}", dup);
-                    self.refined_spans.push(dup);
+                    self.push_refined_span(dup);
                 }
             }
-            self.refined_spans.push(pre_closure);
+            self.push_refined_span(pre_closure);
         }
         if has_post_closure_span {
-            // Update prev.span to start after the closure (and discard curr)
+            // Mutate `prev.span()` to start after the closure (and discard curr).
+            // (**NEVER** update `prev_original_span` because it affects the assumptions
+            // about how the `CoverageSpan`s are ordered.)
             self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
-            self.prev_original_span = self.prev().span;
+            debug!("  Mutated prev.span to start after the closure. prev={:?}", self.prev());
             for dup in pending_dups.iter_mut() {
+                debug!("    ...and at least one overlapping dup={:?}", dup);
                 dup.span = dup.span.with_lo(right_cutoff);
             }
             self.pending_dups.append(&mut pending_dups);
             let closure_covspan = self.take_curr();
-            self.refined_spans.push(closure_covspan); // since self.prev() was already updated
+            self.push_refined_span(closure_covspan); // since self.prev() was already updated
         } else {
             pending_dups.clear();
         }
     }
 
     /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
-    /// `pending_dups` spans, if any); but keep in mind, `prev.span` may start at a `Span.lo()` that
-    /// is less than (further left of) `prev_original_span.lo()`.
+    /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
+    /// If prev.span() was merged into other spans (with matching BCB, for instance),
+    /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`.
+    /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
+    /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is
+    /// not as important as knowing that `prev()` **used to have the same span** as `curr(),
+    /// which means their sort order is still meaningful for determinating the dominator
+    /// relationship.
     ///
     /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
     /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
@@ -640,7 +779,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
             } else {
                 debug!("  ... adding modified prev={:?}", self.prev());
                 let prev = self.take_prev();
-                self.refined_spans.push(prev);
+                self.push_refined_span(prev);
             }
         } else {
             // with `pending_dups`, `prev` cannot have any statements that don't overlap
@@ -653,10 +792,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
     }
 }
 
+/// See `function_source_span()` for a description of the two returned spans.
+/// If the MIR `Statement` is not contributive to computing coverage spans,
+/// returns `None`.
 pub(super) fn filtered_statement_span(
     statement: &'a Statement<'tcx>,
     body_span: Span,
-) -> Option<Span> {
+) -> Option<(Span, Span)> {
     match statement.kind {
         // These statements have spans that are often outside the scope of the executed source code
         // for their parent `BasicBlock`.
@@ -698,10 +840,13 @@ pub(super) fn filtered_statement_span(
     }
 }
 
+/// See `function_source_span()` for a description of the two returned spans.
+/// If the MIR `Terminator` is not contributive to computing coverage spans,
+/// returns `None`.
 pub(super) fn filtered_terminator_span(
     terminator: &'a Terminator<'tcx>,
     body_span: Span,
-) -> Option<Span> {
+) -> Option<(Span, Span)> {
     match terminator.kind {
         // These terminators have spans that don't positively contribute to computing a reasonable
         // span of actually executed source code. (For example, SwitchInt terminators extracted from
@@ -717,11 +862,21 @@ pub(super) fn filtered_terminator_span(
         | TerminatorKind::FalseEdge { .. }
         | TerminatorKind::Goto { .. } => None,
 
+        // Call `func` operand can have a more specific span when part of a chain of calls
+        | TerminatorKind::Call { ref func, .. } => {
+            let mut span = terminator.source_info.span;
+            if let mir::Operand::Constant(box constant) = func {
+                if constant.span.lo() > span.lo() {
+                    span = span.with_lo(constant.span.lo());
+                }
+            }
+            Some(function_source_span(span, body_span))
+        }
+
         // Retain spans from all other terminators
         TerminatorKind::Resume
         | TerminatorKind::Abort
         | TerminatorKind::Return
-        | TerminatorKind::Call { .. }
         | TerminatorKind::Yield { .. }
         | TerminatorKind::GeneratorDrop
         | TerminatorKind::FalseUnwind { .. }
@@ -731,8 +886,23 @@ pub(super) fn filtered_terminator_span(
     }
 }
 
+/// Returns two spans from the given span (the span associated with a
+/// `Statement` or `Terminator`):
+///
+///   1. An extrapolated span (pre-expansion[^1]) corresponding to a range within
+///      the function's body source. This span is guaranteed to be contained
+///      within, or equal to, the `body_span`. If the extrapolated span is not
+///      contained within the `body_span`, the `body_span` is returned.
+///   2. The actual `span` value from the `Statement`, before expansion.
+///
+/// Only the first span is used when computing coverage code regions. The second
+/// span is useful if additional expansion data is needed (such as to look up
+/// the macro name for a composed span within that macro).)
+///
+/// [^1]Expansions result from Rust syntax including macros, syntactic
+/// sugar, etc.).
 #[inline]
-fn function_source_span(span: Span, body_span: Span) -> Span {
-    let span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
-    if body_span.contains(span) { span } else { body_span }
+fn function_source_span(span: Span, body_span: Span) -> (Span, Span) {
+    let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
+    (if body_span.contains(original_span) { original_span } else { body_span }, span)
 }
diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs
index dee112443d3..9b84173c8a2 100644
--- a/compiler/rustc_mir/src/transform/coverage/tests.rs
+++ b/compiler/rustc_mir/src/transform/coverage/tests.rs
@@ -1,6 +1,10 @@
 //! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR
 //! pass.
 //!
+//! ```shell
+//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage'
+//! ```
+//!
 //! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage`
 //! functions and algorithms. Mocked objects include instances of `mir::Body`; including
 //! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on
@@ -679,10 +683,15 @@ fn test_make_bcb_counters() {
         let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
         let mut coverage_spans = Vec::new();
         for (bcb, data) in basic_coverage_blocks.iter_enumerated() {
-            if let Some(span) =
+            if let Some((span, expn_span)) =
                 spans::filtered_terminator_span(data.terminator(&mir_body), body_span)
             {
-                coverage_spans.push(spans::CoverageSpan::for_terminator(span, bcb, data.last_bb()));
+                coverage_spans.push(spans::CoverageSpan::for_terminator(
+                    span,
+                    expn_span,
+                    bcb,
+                    data.last_bb(),
+                ));
             }
         }
         let mut coverage_counters = counters::CoverageCounters::new(0);
diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs
index a9a30e407b4..9abfa4a8dc6 100644
--- a/compiler/rustc_mir/src/util/spanview.rs
+++ b/compiler/rustc_mir/src/util/spanview.rs
@@ -99,7 +99,11 @@ where
     W: Write,
 {
     let def_id = body.source.def_id();
-    let body_span = hir_body(tcx, def_id).value.span;
+    let hir_body = hir_body(tcx, def_id);
+    if hir_body.is_none() {
+        return Ok(());
+    }
+    let body_span = hir_body.unwrap().value.span;
     let mut span_viewables = Vec::new();
     for (bb, data) in body.basic_blocks().iter_enumerated() {
         match spanview {
@@ -664,19 +668,16 @@ fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
     let hir_id =
         tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
     let fn_decl_span = tcx.hir().span(hir_id);
-    let body_span = hir_body(tcx, def_id).value.span;
-    if fn_decl_span.ctxt() == body_span.ctxt() {
-        fn_decl_span.to(body_span)
+    if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
+        if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span }
     } else {
-        // This probably occurs for functions defined via macros
-        body_span
+        fn_decl_span
     }
 }
 
-fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
+fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::Body<'tcx>> {
     let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
-    let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
-    tcx.hir().body(fn_body_id)
+    hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id))
 }
 
 fn escape_html(s: &str) -> String {
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 5c4a2785d6e..0c43e304f1e 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -61,7 +61,8 @@ impl<'a> Parser<'a> {
                 },
                 _ => false,
             },
-            NonterminalKind::Pat2015 { .. } | NonterminalKind::Pat2021 { .. } => match token.kind {
+            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
+                match token.kind {
                 token::Ident(..) |                  // box, ref, mut, and other identifiers (can stricten)
                 token::OpenDelim(token::Paren) |    // tuple pattern
                 token::OpenDelim(token::Bracket) |  // slice pattern
@@ -75,10 +76,11 @@ impl<'a> Parser<'a> {
                 token::Lt |                         // path (UFCS constant)
                 token::BinOp(token::Shl) => true,   // path (double UFCS)
                 // leading vert `|` or-pattern
-                token::BinOp(token::Or) =>  matches!(kind, NonterminalKind::Pat2021 {..}),
+                token::BinOp(token::Or) =>  matches!(kind, NonterminalKind::PatWithOr {..}),
                 token::Interpolated(ref nt) => may_be_ident(nt),
                 _ => false,
-            },
+            }
+            }
             NonterminalKind::Lifetime => match token.kind {
                 token::Lifetime(_) => true,
                 token::Interpolated(ref nt) => {
@@ -118,10 +120,10 @@ impl<'a> Parser<'a> {
                     return Err(self.struct_span_err(self.token.span, "expected a statement"));
                 }
             },
-            NonterminalKind::Pat2015 { .. } | NonterminalKind::Pat2021 { .. } => {
+            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
                 token::NtPat(self.collect_tokens_no_attrs(|this| match kind {
-                    NonterminalKind::Pat2015 { .. } => this.parse_pat_no_top_alt(None),
-                    NonterminalKind::Pat2021 { .. } => {
+                    NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None),
+                    NonterminalKind::PatWithOr { .. } => {
                         this.parse_pat_allow_top_alt(None, RecoverComma::No)
                     }
                     _ => unreachable!(),
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index c63edf365a1..d32180525bf 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -472,7 +472,9 @@ fn create_and_seed_worklist<'tcx>(
         )
         .chain(
             // Seed entry point
-            tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().local_def_id_to_hir_id(def_id)),
+            tcx.entry_fn(LOCAL_CRATE).and_then(|(def_id, _)| {
+                def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+            }),
         )
         .collect::<Vec<_>>();
 
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index e1b750df33c..65cfe986ad4 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,12 +1,13 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem, CRATE_HIR_ID};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{CrateType, EntryFnType};
+use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
@@ -16,9 +17,6 @@ struct EntryContext<'a, 'tcx> {
 
     map: Map<'tcx>,
 
-    /// The top-level function called `main`.
-    main_fn: Option<(HirId, Span)>,
-
     /// The function that has attribute named `main`.
     attr_main_fn: Option<(HirId, Span)>,
 
@@ -50,7 +48,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
     }
 }
 
-fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
+fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> {
     assert_eq!(cnum, LOCAL_CRATE);
 
     let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
@@ -67,7 +65,6 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
     let mut ctxt = EntryContext {
         session: tcx.sess,
         map: tcx.hir(),
-        main_fn: None,
         attr_main_fn: None,
         start_fn: None,
         non_main_fns: Vec::new(),
@@ -115,14 +112,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
                 throw_attr_err(&ctxt.session, attr.span, "rustc_main");
             }
         }
-        EntryPointType::MainNamed => {
-            if ctxt.main_fn.is_none() {
-                ctxt.main_fn = Some((item.hir_id(), item.span));
-            } else {
-                struct_span_err!(ctxt.session, item.span, E0136, "multiple `main` functions")
-                    .emit();
-            }
-        }
+        EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
             ctxt.non_main_fns.push((item.hir_id(), item.span));
         }
@@ -154,16 +144,23 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
     }
 }
 
-fn configure_main(
-    tcx: TyCtxt<'_>,
-    visitor: &EntryContext<'_, '_>,
-) -> Option<(LocalDefId, EntryFnType)> {
+fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
     if let Some((hir_id, _)) = visitor.start_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Start))
+        Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start))
     } else if let Some((hir_id, _)) = visitor.attr_main_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
-    } else if let Some((hir_id, _)) = visitor.main_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
+        Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main))
+    } else if let Some(def_id) = tcx.main_def.and_then(|main_def| main_def.opt_fn_def_id()) {
+        if tcx.main_def.unwrap().is_import && !tcx.features().imported_main {
+            let span = tcx.main_def.unwrap().span;
+            feature_err(
+                &tcx.sess.parse_sess,
+                sym::imported_main,
+                span,
+                "using an imported function as entry point `main` is experimental",
+            )
+            .emit();
+        }
+        Some((def_id, EntryFnType::Main))
     } else {
         no_main_err(tcx, visitor);
         None
@@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
     } else {
         err.note(&note);
     }
+
+    if let Some(main_def) = tcx.main_def {
+        if main_def.opt_fn_def_id().is_none() {
+            // There is something at `crate::main`, but it is not a function definition.
+            err.span_label(main_def.span, &format!("non-function item at `crate::main` is found"));
+        }
+    }
+
     if tcx.sess.teach(&err.get_code().unwrap()) {
         err.note(
             "If you don't know the basics of Rust, you can go look to the Rust Book \
@@ -222,7 +227,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
     err.emit();
 }
 
-pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(LocalDefId, EntryFnType)> {
+pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
     tcx.entry_fn(LOCAL_CRATE)
 }
 
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 24485889731..2517793ecea 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -250,8 +250,8 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
             // need to invoke queries itself, we cannot keep the query caches
             // locked while doing so. Instead we copy out the
             // `(query_key, dep_node_index)` pairs and release the lock again.
-            let query_keys_and_indices: Vec<_> = query_cache
-                .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());
+            let mut query_keys_and_indices = Vec::new();
+            query_cache.iter_results(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i)));
 
             // Now actually allocate the strings. If allocating the strings
             // generates new entries in the query cache, we'll miss them but
@@ -275,14 +275,15 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
             let query_name = profiler.get_or_alloc_cached_string(query_name);
             let event_id = event_id_builder.from_label(query_name).to_string_id();
 
-            query_cache.iter_results(|results| {
-                let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();
-
-                profiler.bulk_map_query_invocation_id_to_single_string(
-                    query_invocation_ids.into_iter(),
-                    event_id,
-                );
+            let mut query_invocation_ids = Vec::new();
+            query_cache.iter_results(&mut |_, _, i| {
+                query_invocation_ids.push(i.into());
             });
+
+            profiler.bulk_map_query_invocation_id_to_single_string(
+                query_invocation_ids.into_iter(),
+                event_id,
+            );
         }
     });
 }
diff --git a/compiler/rustc_query_impl/src/stats.rs b/compiler/rustc_query_impl/src/stats.rs
index 4d52483c3b8..e877034bd7b 100644
--- a/compiler/rustc_query_impl/src/stats.rs
+++ b/compiler/rustc_query_impl/src/stats.rs
@@ -50,13 +50,12 @@ where
         key_type: type_name::<C::Key>(),
         value_size: mem::size_of::<C::Value>(),
         value_type: type_name::<C::Value>(),
-        entry_count: map.iter_results(|results| results.count()),
+        entry_count: 0,
         local_def_id_keys: None,
     };
-    map.iter_results(|results| {
-        for (key, _, _) in results {
-            key.key_stats(&mut stats)
-        }
+    map.iter_results(&mut |key, _, _| {
+        stats.entry_count += 1;
+        key.key_stats(&mut stats)
     });
     stats
 }
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index 001bf3b216b..2e4c8d0565a 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -49,13 +49,11 @@ pub trait QueryCache: QueryStorage {
         index: DepNodeIndex,
     ) -> Self::Stored;
 
-    fn iter<R>(
+    fn iter(
         &self,
         shards: &Sharded<Self::Sharded>,
-        f: impl for<'a> FnOnce(
-            &'a mut dyn Iterator<Item = (&'a Self::Key, &'a Self::Value, DepNodeIndex)>,
-        ) -> R,
-    ) -> R;
+        f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
+    );
 }
 
 pub struct DefaultCacheSelector;
@@ -124,14 +122,17 @@ where
         value
     }
 
-    fn iter<R>(
+    fn iter(
         &self,
         shards: &Sharded<Self::Sharded>,
-        f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R,
-    ) -> R {
+        f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
+    ) {
         let shards = shards.lock_shards();
-        let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1));
-        f(&mut results)
+        for shard in shards.iter() {
+            for (k, v) in shard.iter() {
+                f(k, &v.0, v.1);
+            }
+        }
     }
 }
 
@@ -207,13 +208,16 @@ where
         &value.0
     }
 
-    fn iter<R>(
+    fn iter(
         &self,
         shards: &Sharded<Self::Sharded>,
-        f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R,
-    ) -> R {
+        f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
+    ) {
         let shards = shards.lock_shards();
-        let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1));
-        f(&mut results)
+        for shard in shards.iter() {
+            for (k, v) in shard.iter() {
+                f(k, &v.0, v.1);
+            }
+        }
     }
 }
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index fb8a53048fa..c9125b3ffe9 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -73,12 +73,7 @@ impl<C: QueryCache> QueryCacheStore<C> {
         (QueryLookup { key_hash, shard }, lock)
     }
 
-    pub fn iter_results<R>(
-        &self,
-        f: impl for<'a> FnOnce(
-            &'a mut dyn Iterator<Item = (&'a C::Key, &'a C::Value, DepNodeIndex)>,
-        ) -> R,
-    ) -> R {
+    pub fn iter_results(&self, f: &mut dyn FnMut(&C::Key, &C::Value, DepNodeIndex)) {
         self.cache.iter(&self.shards, f)
     }
 }
@@ -130,18 +125,15 @@ where
         // We use try_lock_shards here since we are called from the
         // deadlock handler, and this shouldn't be locked.
         let shards = self.shards.try_lock_shards()?;
-        let shards = shards.iter().enumerate();
-        jobs.extend(shards.flat_map(|(shard_id, shard)| {
-            shard.active.iter().filter_map(move |(k, v)| {
+        for (shard_id, shard) in shards.iter().enumerate() {
+            for (k, v) in shard.active.iter() {
                 if let QueryResult::Started(ref job) = *v {
                     let id = QueryJobId::new(job.id, shard_id, kind);
                     let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) };
-                    Some((id, QueryJobInfo { info, job: job.clone() }))
-                } else {
-                    None
+                    jobs.insert(id, QueryJobInfo { info, job: job.clone() });
                 }
-            })
-        }));
+            }
+        }
 
         Some(())
     }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index c5f12c0c691..6ea46f5c528 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -487,7 +487,13 @@ impl<'a> Resolver<'a> {
                         name
                     ));
                 }
-                err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions");
+
+                if self.session.is_nightly_build() {
+                    err.help(
+                        "use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` \
+                        to allow generic const expressions"
+                    );
+                }
 
                 err
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 1d1969f7e78..9197f4059ca 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -50,7 +50,7 @@ use rustc_middle::hir::exports::ExportMap;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, ResolverOutputs};
+use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
 use rustc_session::lint;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::Session;
@@ -1021,6 +1021,8 @@ pub struct Resolver<'a> {
     trait_impl_items: FxHashSet<LocalDefId>,
 
     legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
+
+    main_def: Option<MainDefinition>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1348,6 +1350,7 @@ impl<'a> Resolver<'a> {
             next_disambiguator: Default::default(),
             trait_impl_items: Default::default(),
             legacy_const_generic_args: Default::default(),
+            main_def: Default::default(),
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1382,6 +1385,7 @@ impl<'a> Resolver<'a> {
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
         let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
+        let main_def = self.main_def;
         ResolverOutputs {
             definitions,
             cstore: Box::new(self.crate_loader.into_cstore()),
@@ -1396,6 +1400,7 @@ impl<'a> Resolver<'a> {
                 .iter()
                 .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
                 .collect(),
+            main_def,
         }
     }
 
@@ -1414,6 +1419,7 @@ impl<'a> Resolver<'a> {
                 .iter()
                 .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
                 .collect(),
+            main_def: self.main_def.clone(),
         }
     }
 
@@ -1459,6 +1465,7 @@ impl<'a> Resolver<'a> {
             self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
             self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
             self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
+            self.session.time("resolve_main", || self.resolve_main());
             self.session.time("resolve_check_unused", || self.check_unused(krate));
             self.session.time("resolve_report_errors", || self.report_errors(krate));
             self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
@@ -3350,6 +3357,32 @@ impl<'a> Resolver<'a> {
         }
         None
     }
+
+    fn resolve_main(&mut self) {
+        let module = self.graph_root;
+        let ident = Ident::with_dummy_span(sym::main);
+        let parent_scope = &ParentScope::module(module, self);
+
+        let name_binding = match self.resolve_ident_in_module(
+            ModuleOrUniformRoot::Module(module),
+            ident,
+            ValueNS,
+            parent_scope,
+            false,
+            DUMMY_SP,
+        ) {
+            Ok(name_binding) => name_binding,
+            _ => return,
+        };
+
+        let res = name_binding.res();
+        let is_import = name_binding.is_import();
+        let span = name_binding.span;
+        if let Res::Def(DefKind::Fn, _) = res {
+            self.record_use(ident, ValueNS, name_binding, false);
+        }
+        self.main_def = Some(MainDefinition { res, is_import, span });
+    }
 }
 
 fn names_to_string(names: &[Symbol]) -> String {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 52a6e4ff924..1f5cb5b8abc 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -156,7 +156,7 @@ pub enum InstrumentCoverage {
     Off,
 }
 
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Clone, PartialEq, Hash, Debug)]
 pub enum LinkerPluginLto {
     LinkerPlugin(PathBuf),
     LinkerPluginAuto,
@@ -172,7 +172,7 @@ impl LinkerPluginLto {
     }
 }
 
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Clone, PartialEq, Hash, Debug)]
 pub enum SwitchWithOptPath {
     Enabled(Option<PathBuf>),
     Disabled,
@@ -702,6 +702,7 @@ impl Default for Options {
             cli_forced_codegen_units: None,
             cli_forced_thinlto_off: false,
             remap_path_prefix: Vec::new(),
+            real_rust_source_base_dir: None,
             edition: DEFAULT_EDITION,
             json_artifact_notifications: false,
             json_unused_externs: false,
@@ -778,7 +779,7 @@ pub enum CrateType {
 
 impl_stable_hash_via_hash!(CrateType);
 
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Passes {
     Some(Vec<String>),
     All,
@@ -1980,6 +1981,34 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         }
     }
 
+    // Try to find a directory containing the Rust `src`, for more details see
+    // the doc comment on the `real_rust_source_base_dir` field.
+    let tmp_buf;
+    let sysroot = match &sysroot_opt {
+        Some(s) => s,
+        None => {
+            tmp_buf = crate::filesearch::get_or_default_sysroot();
+            &tmp_buf
+        }
+    };
+    let real_rust_source_base_dir = {
+        // This is the location used by the `rust-src` `rustup` component.
+        let mut candidate = sysroot.join("lib/rustlib/src/rust");
+        if let Ok(metadata) = candidate.symlink_metadata() {
+            // Replace the symlink rustbuild creates, with its destination.
+            // We could try to use `fs::canonicalize` instead, but that might
+            // produce unnecessarily verbose path.
+            if metadata.file_type().is_symlink() {
+                if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
+                    candidate = symlink_dest;
+                }
+            }
+        }
+
+        // Only use this directory if it has a file we can expect to always find.
+        if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
+    };
+
     Options {
         crate_types,
         optimize: opt_level,
@@ -2010,6 +2039,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         cli_forced_codegen_units: codegen_units,
         cli_forced_thinlto_off: disable_thinlto,
         remap_path_prefix,
+        real_rust_source_base_dir,
         edition,
         json_artifact_notifications,
         json_unused_externs,
@@ -2374,6 +2404,7 @@ crate mod dep_tracking {
 
     impl_dep_tracking_hash_for_sortable_vec_of!(String);
     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
+    impl_dep_tracking_hash_for_sortable_vec_of!((PathBuf, PathBuf));
     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index fd26f50da5a..735188768e4 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -20,73 +20,112 @@ use std::num::NonZeroUsize;
 use std::path::PathBuf;
 use std::str;
 
-macro_rules! hash_option {
-    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => {{}};
-    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => {{
+macro_rules! insert {
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr) => {
         if $sub_hashes
             .insert(stringify!($opt_name), $opt_expr as &dyn dep_tracking::DepTrackingHash)
             .is_some()
         {
             panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
         }
+    };
+}
+
+macro_rules! hash_opt {
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [UNTRACKED]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [TRACKED]) => {{ insert!($opt_name, $opt_expr, $sub_hashes) }};
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $for_crate_hash: ident, [TRACKED_NO_CRATE_HASH]) => {{
+        if !$for_crate_hash {
+            insert!($opt_name, $opt_expr, $sub_hashes)
+        }
     }};
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [SUBSTRUCT]) => {{}};
+}
+
+macro_rules! hash_substruct {
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [UNTRACKED]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED_NO_CRATE_HASH]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [SUBSTRUCT]) => {
+        use crate::config::dep_tracking::DepTrackingHash;
+        $opt_expr.dep_tracking_hash($for_crate_hash, $error_format).hash($hasher, $error_format);
+    };
 }
 
 macro_rules! top_level_options {
-    (pub struct Options { $(
-        $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
+    ( $( #[$top_level_attr:meta] )* pub struct Options { $(
+        $( #[$attr:meta] )*
+        $opt:ident : $t:ty [$dep_tracking_marker:ident],
     )* } ) => (
         #[derive(Clone)]
+        $( #[$top_level_attr] )*
         pub struct Options {
-            $(pub $opt: $t),*
+            $(
+                $( #[$attr] )*
+                pub $opt: $t
+            ),*
         }
 
         impl Options {
-            pub fn dep_tracking_hash(&self) -> u64 {
+            pub fn dep_tracking_hash(&self, for_crate_hash: bool) -> u64 {
                 let mut sub_hashes = BTreeMap::new();
                 $({
-                    hash_option!($opt,
-                                 &self.$opt,
-                                 &mut sub_hashes,
-                                 [$dep_tracking_marker $($warn_val,
-                                                         $warn_text,
-                                                         self.error_format)*]);
+                    hash_opt!($opt,
+                                &self.$opt,
+                                &mut sub_hashes,
+                                for_crate_hash,
+                                [$dep_tracking_marker]);
                 })*
                 let mut hasher = DefaultHasher::new();
                 dep_tracking::stable_hash(sub_hashes,
                                           &mut hasher,
                                           self.error_format);
+                $({
+                    hash_substruct!($opt,
+                        &self.$opt,
+                        self.error_format,
+                        for_crate_hash,
+                        &mut hasher,
+                        [$dep_tracking_marker]);
+                })*
                 hasher.finish()
             }
         }
     );
 }
 
-// The top-level command-line options struct.
-//
-// For each option, one has to specify how it behaves with regard to the
-// dependency tracking system of incremental compilation. This is done via the
-// square-bracketed directive after the field type. The options are:
-//
-// [TRACKED]
-// A change in the given field will cause the compiler to completely clear the
-// incremental compilation cache before proceeding.
-//
-// [UNTRACKED]
-// Incremental compilation is not influenced by this option.
-//
-// If you add a new option to this struct or one of the sub-structs like
-// `CodegenOptions`, think about how it influences incremental compilation. If in
-// doubt, specify [TRACKED], which is always "correct" but might lead to
-// unnecessary re-compilation.
 top_level_options!(
+    /// The top-level command-line options struct.
+    ///
+    /// For each option, one has to specify how it behaves with regard to the
+    /// dependency tracking system of incremental compilation. This is done via the
+    /// square-bracketed directive after the field type. The options are:
+    ///
+    /// - `[TRACKED]`
+    /// A change in the given field will cause the compiler to completely clear the
+    /// incremental compilation cache before proceeding.
+    ///
+    /// - `[TRACKED_NO_CRATE_HASH]`
+    /// Same as `[TRACKED]`, but will not affect the crate hash. This is useful for options that only
+    /// affect the incremental cache.
+    ///
+    /// - `[UNTRACKED]`
+    /// Incremental compilation is not influenced by this option.
+    ///
+    /// - `[SUBSTRUCT]`
+    /// Second-level sub-structs containing more options.
+    ///
+    /// If you add a new option to this struct or one of the sub-structs like
+    /// `CodegenOptions`, think about how it influences incremental compilation. If in
+    /// doubt, specify `[TRACKED]`, which is always "correct" but might lead to
+    /// unnecessary re-compilation.
     pub struct Options {
-        // The crate config requested for the session, which may be combined
-        // with additional crate configurations during the compile process.
+        /// The crate config requested for the session, which may be combined
+        /// with additional crate configurations during the compile process.
         crate_types: Vec<CrateType> [TRACKED],
         optimize: OptLevel [TRACKED],
-        // Include the `debug_assertions` flag in dependency tracking, since it
-        // can influence whether overflow checks are done or not.
+        /// Include the `debug_assertions` flag in dependency tracking, since it
+        /// can influence whether overflow checks are done or not.
         debug_assertions: bool [TRACKED],
         debuginfo: DebugInfo [TRACKED],
         lint_opts: Vec<(String, lint::Level)> [TRACKED],
@@ -102,52 +141,60 @@ top_level_options!(
         test: bool [TRACKED],
         error_format: ErrorOutputType [UNTRACKED],
 
-        // If `Some`, enable incremental compilation, using the given
-        // directory to store intermediate results.
+        /// If `Some`, enable incremental compilation, using the given
+        /// directory to store intermediate results.
         incremental: Option<PathBuf> [UNTRACKED],
 
-        debugging_opts: DebuggingOptions [TRACKED],
+        debugging_opts: DebuggingOptions [SUBSTRUCT],
         prints: Vec<PrintRequest> [UNTRACKED],
-        // Determines which borrow checker(s) to run. This is the parsed, sanitized
-        // version of `debugging_opts.borrowck`, which is just a plain string.
+        /// Determines which borrow checker(s) to run. This is the parsed, sanitized
+        /// version of `debugging_opts.borrowck`, which is just a plain string.
         borrowck_mode: BorrowckMode [UNTRACKED],
-        cg: CodegenOptions [TRACKED],
+        cg: CodegenOptions [SUBSTRUCT],
         externs: Externs [UNTRACKED],
         extern_dep_specs: ExternDepSpecs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
-        // An optional name to use as the crate for std during std injection,
-        // written `extern crate name as std`. Defaults to `std`. Used by
-        // out-of-tree drivers.
+        /// An optional name to use as the crate for std during std injection,
+        /// written `extern crate name as std`. Defaults to `std`. Used by
+        /// out-of-tree drivers.
         alt_std_name: Option<String> [TRACKED],
-        // Indicates how the compiler should treat unstable features.
+        /// Indicates how the compiler should treat unstable features.
         unstable_features: UnstableFeatures [TRACKED],
 
-        // Indicates whether this run of the compiler is actually rustdoc. This
-        // is currently just a hack and will be removed eventually, so please
-        // try to not rely on this too much.
+        /// Indicates whether this run of the compiler is actually rustdoc. This
+        /// is currently just a hack and will be removed eventually, so please
+        /// try to not rely on this too much.
         actually_rustdoc: bool [TRACKED],
 
-        // Control path trimming.
+        /// Control path trimming.
         trimmed_def_paths: TrimmedDefPaths [TRACKED],
 
-        // Specifications of codegen units / ThinLTO which are forced as a
-        // result of parsing command line options. These are not necessarily
-        // what rustc was invoked with, but massaged a bit to agree with
-        // commands like `--emit llvm-ir` which they're often incompatible with
-        // if we otherwise use the defaults of rustc.
+        /// Specifications of codegen units / ThinLTO which are forced as a
+        /// result of parsing command line options. These are not necessarily
+        /// what rustc was invoked with, but massaged a bit to agree with
+        /// commands like `--emit llvm-ir` which they're often incompatible with
+        /// if we otherwise use the defaults of rustc.
         cli_forced_codegen_units: Option<usize> [UNTRACKED],
         cli_forced_thinlto_off: bool [UNTRACKED],
 
-        // Remap source path prefixes in all output (messages, object files, debug, etc.).
-        remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+        /// Remap source path prefixes in all output (messages, object files, debug, etc.).
+        remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
+        /// Base directory containing the `src/` for the Rust standard library, and
+        /// potentially `rustc` as well, if we can can find it. Right now it's always
+        /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
+        ///
+        /// This directory is what the virtual `/rustc/$hash` is translated back to,
+        /// if Rust was built with path remapping to `/rustc/$hash` enabled
+        /// (the `rust.remap-debuginfo` option in `config.toml`).
+        real_rust_source_base_dir: Option<PathBuf> [TRACKED_NO_CRATE_HASH],
 
         edition: Edition [TRACKED],
 
-        // `true` if we're emitting JSON blobs about each artifact produced
-        // by the compiler.
+        /// `true` if we're emitting JSON blobs about each artifact produced
+        /// by the compiler.
         json_artifact_notifications: bool [TRACKED],
 
-        // `true` if we're emitting a JSON blob containing the unused externs
+        /// `true` if we're emitting a JSON blob containing the unused externs
         json_unused_externs: bool [UNTRACKED],
 
         pretty: Option<PpMode> [UNTRACKED],
@@ -165,11 +212,11 @@ top_level_options!(
 macro_rules! options {
     ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
      $buildfn:ident, $prefix:expr, $outputname:expr,
-     $stat:ident, $mod_desc:ident, $mod_set:ident,
-     $($opt:ident : $t:ty = (
+     $stat:ident,
+     $($( #[$attr:meta] )* $opt:ident : $t:ty = (
         $init:expr,
         $parse:ident,
-        [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
+        [$dep_tracking_marker:ident],
         $desc:expr)
      ),* ,) =>
 (
@@ -177,7 +224,7 @@ macro_rules! options {
     pub struct $struct_name { $(pub $opt: $t),* }
 
     pub fn $defaultfn() -> $struct_name {
-        $struct_name { $($opt: $init),* }
+        $struct_name { $( $( #[$attr] )* $opt: $init),* }
     }
 
     pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
@@ -219,563 +266,590 @@ macro_rules! options {
         return op;
     }
 
-    impl dep_tracking::DepTrackingHash for $struct_name {
-        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+    impl $struct_name {
+        fn dep_tracking_hash(&self, _for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
             let mut sub_hashes = BTreeMap::new();
             $({
-                hash_option!($opt,
-                             &self.$opt,
-                             &mut sub_hashes,
-                             [$dep_tracking_marker $($dep_warn_val,
-                                                     $dep_warn_text,
-                                                     error_format)*]);
+                hash_opt!($opt,
+                            &self.$opt,
+                            &mut sub_hashes,
+                            _for_crate_hash,
+                            [$dep_tracking_marker]);
             })*
-            dep_tracking::stable_hash(sub_hashes, hasher, error_format);
+            let mut hasher = DefaultHasher::new();
+            dep_tracking::stable_hash(sub_hashes,
+                                        &mut hasher,
+                                        error_format);
+            hasher.finish()
         }
     }
 
     pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
     pub const $stat: &[(&str, $setter_name, &str, &str)] =
-        &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
-
-    #[allow(non_upper_case_globals, dead_code)]
-    mod $mod_desc {
-        pub const parse_no_flag: &str = "no value";
-        pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`";
-        pub const parse_opt_bool: &str = parse_bool;
-        pub const parse_string: &str = "a string";
-        pub const parse_opt_string: &str = parse_string;
-        pub const parse_string_push: &str = parse_string;
-        pub const parse_opt_pathbuf: &str = "a path";
-        pub const parse_pathbuf_push: &str = parse_opt_pathbuf;
-        pub const parse_list: &str = "a space-separated list of strings";
-        pub const parse_opt_list: &str = parse_list;
-        pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
-        pub const parse_number: &str = "a number";
-        pub const parse_opt_number: &str = parse_number;
-        pub const parse_threads: &str = parse_number;
-        pub const parse_passes: &str = "a space-separated list of passes, or `all`";
-        pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
-        pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-        pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
-        pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
-        pub const parse_cfguard: &str =
-            "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
-        pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
-        pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
-        pub const parse_optimization_fuel: &str = "crate=integer";
-        pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
-        pub const parse_instrument_coverage: &str = "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
-        pub const parse_unpretty: &str = "`string` or `string=string`";
-        pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
-        pub const parse_lto: &str =
-            "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
-        pub const parse_linker_plugin_lto: &str =
-            "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
-        pub const parse_switch_with_opt_path: &str =
-            "an optional path to the profiling data output directory";
-        pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
-        pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
-        pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
-        pub const parse_relocation_model: &str =
-            "one of supported relocation models (`rustc --print relocation-models`)";
-        pub const parse_code_model: &str =
-            "one of supported code models (`rustc --print code-models`)";
-        pub const parse_tls_model: &str =
-            "one of supported TLS models (`rustc --print tls-models`)";
-        pub const parse_target_feature: &str = parse_string;
-        pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
-        pub const parse_split_debuginfo: &str =
-            "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+        &[ $( (stringify!($opt), crate::options::parse::$opt, $crate::options::desc::$parse, $desc) ),* ];
+
+    // Sometimes different options need to build a common structure.
+    // That structure can kept in one of the options' fields, the others become dummy.
+    macro_rules! redirect_field {
+        ($cg:ident.link_arg) => { $cg.link_args };
+        ($cg:ident.pre_link_arg) => { $cg.pre_link_args };
+        ($cg:ident.$field:ident) => { $cg.$field };
     }
 
-    #[allow(dead_code)]
-    mod $mod_set {
-        use super::*;
-        use std::str::FromStr;
-
-        // Sometimes different options need to build a common structure.
-        // That structure can kept in one of the options' fields, the others become dummy.
-        macro_rules! redirect_field {
-            ($cg:ident.link_arg) => { $cg.link_args };
-            ($cg:ident.pre_link_arg) => { $cg.pre_link_args };
-            ($cg:ident.$field:ident) => { $cg.$field };
+    $(
+        pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
+            $crate::options::parse::$parse(&mut redirect_field!(cg.$opt), v)
         }
+    )*
 
-        $(
-            pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
-                $parse(&mut redirect_field!(cg.$opt), v)
-            }
-        )*
-
-        /// This is for boolean options that don't take a value and start with
-        /// `no-`. This style of option is deprecated.
-        fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
-            match v {
-                None => { *slot = true; true }
-                Some(_) => false,
-            }
-        }
+) }
 
-        /// Use this for any boolean option that has a static default.
-        fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
-            match v {
-                Some("y") | Some("yes") | Some("on") | None => { *slot = true; true }
-                Some("n") | Some("no") | Some("off") => { *slot = false; true }
-                _ => false,
-            }
-        }
+#[allow(non_upper_case_globals)]
+mod desc {
+    pub const parse_no_flag: &str = "no value";
+    pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`";
+    pub const parse_opt_bool: &str = parse_bool;
+    pub const parse_string: &str = "a string";
+    pub const parse_opt_string: &str = parse_string;
+    pub const parse_string_push: &str = parse_string;
+    pub const parse_opt_pathbuf: &str = "a path";
+    pub const parse_list: &str = "a space-separated list of strings";
+    pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
+    pub const parse_number: &str = "a number";
+    pub const parse_opt_number: &str = parse_number;
+    pub const parse_threads: &str = parse_number;
+    pub const parse_passes: &str = "a space-separated list of passes, or `all`";
+    pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
+    pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
+    pub const parse_sanitizers: &str =
+        "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
+    pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
+    pub const parse_cfguard: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
+    pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
+    pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
+    pub const parse_optimization_fuel: &str = "crate=integer";
+    pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
+    pub const parse_instrument_coverage: &str =
+        "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
+    pub const parse_unpretty: &str = "`string` or `string=string`";
+    pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
+    pub const parse_lto: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
+    pub const parse_linker_plugin_lto: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
+    pub const parse_switch_with_opt_path: &str =
+        "an optional path to the profiling data output directory";
+    pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
+    pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
+    pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
+    pub const parse_relocation_model: &str =
+        "one of supported relocation models (`rustc --print relocation-models`)";
+    pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)";
+    pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)";
+    pub const parse_target_feature: &str = parse_string;
+    pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
+    pub const parse_split_debuginfo: &str =
+        "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+}
 
-        /// Use this for any boolean option that lacks a static default. (The
-        /// actions taken when such an option is not specified will depend on
-        /// other factors, such as other options, or target options.)
-        fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
-            match v {
-                Some("y") | Some("yes") | Some("on") | None => { *slot = Some(true); true }
-                Some("n") | Some("no") | Some("off") => { *slot = Some(false); true }
-                _ => false,
+mod parse {
+    crate use super::*;
+    use std::str::FromStr;
+
+    /// This is for boolean options that don't take a value and start with
+    /// `no-`. This style of option is deprecated.
+    crate fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
+        match v {
+            None => {
+                *slot = true;
+                true
             }
+            Some(_) => false,
         }
+    }
 
-        /// Use this for any string option that has a static default.
-        fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.to_string(); true },
-                None => false,
+    /// Use this for any boolean option that has a static default.
+    crate fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
+        match v {
+            Some("y") | Some("yes") | Some("on") | None => {
+                *slot = true;
+                true
             }
+            Some("n") | Some("no") | Some("off") => {
+                *slot = false;
+                true
+            }
+            _ => false,
         }
+    }
 
-        /// Use this for any string option that lacks a static default.
-        fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = Some(s.to_string()); true },
-                None => false,
+    /// Use this for any boolean option that lacks a static default. (The
+    /// actions taken when such an option is not specified will depend on
+    /// other factors, such as other options, or target options.)
+    crate fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
+        match v {
+            Some("y") | Some("yes") | Some("on") | None => {
+                *slot = Some(true);
+                true
+            }
+            Some("n") | Some("no") | Some("off") => {
+                *slot = Some(false);
+                true
             }
+            _ => false,
         }
+    }
 
-        fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = Some(PathBuf::from(s)); true },
-                None => false,
+    /// Use this for any string option that has a static default.
+    crate fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = s.to_string();
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { slot.push(s.to_string()); true },
-                None => false,
+    /// Use this for any string option that lacks a static default.
+    crate fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = Some(s.to_string());
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { slot.push(PathBuf::from(s)); true },
-                None => false,
+    crate fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = Some(PathBuf::from(s));
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    slot.extend(s.split_whitespace().map(|s| s.to_string()));
-                    true
-                },
-                None => false,
+    crate fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                slot.push(s.to_string());
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    let v = s.split_whitespace().map(|s| s.to_string()).collect();
-                    *slot = Some(v);
-                    true
-                },
-                None => false,
+    crate fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                slot.extend(s.split_whitespace().map(|s| s.to_string()));
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    let v = s.split(',').map(|s| s.to_string()).collect();
-                    *slot = Some(v);
-                    true
-                },
-                None => false,
+    crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
+                v.sort_unstable();
+                *slot = Some(v);
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
-            match v.and_then(|s| s.parse().ok()) {
-                Some(0) => { *slot = ::num_cpus::get(); true },
-                Some(i) => { *slot = i; true },
-                None => false
+    crate fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
+        match v.and_then(|s| s.parse().ok()) {
+            Some(0) => {
+                *slot = ::num_cpus::get();
+                true
+            }
+            Some(i) => {
+                *slot = i;
+                true
             }
+            None => false,
         }
+    }
 
-        /// Use this for any numeric option that has a static default.
-        fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
-            match v.and_then(|s| s.parse().ok()) {
-                Some(i) => { *slot = i; true },
-                None => false
+    /// Use this for any numeric option that has a static default.
+    crate fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
+        match v.and_then(|s| s.parse().ok()) {
+            Some(i) => {
+                *slot = i;
+                true
             }
+            None => false,
         }
+    }
 
-        /// Use this for any numeric option that lacks a static default.
-        fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.parse().ok(); slot.is_some() }
-                None => false
+    /// Use this for any numeric option that lacks a static default.
+    crate fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = s.parse().ok();
+                slot.is_some()
             }
+            None => false,
         }
+    }
 
-        fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
-            match v {
-                Some("all") => {
-                    *slot = Passes::All;
+    crate fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
+        match v {
+            Some("all") => {
+                *slot = Passes::All;
+                true
+            }
+            v => {
+                let mut passes = vec![];
+                if parse_list(&mut passes, v) {
+                    *slot = Passes::Some(passes);
                     true
-                }
-                v => {
-                    let mut passes = vec![];
-                    if parse_list(&mut passes, v) {
-                        *slot = Passes::Some(passes);
-                        true
-                    } else {
-                        false
-                    }
+                } else {
+                    false
                 }
             }
         }
+    }
 
-        fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
-            match v {
-                Some("unwind") => *slot = Some(PanicStrategy::Unwind),
-                Some("abort") => *slot = Some(PanicStrategy::Abort),
-                _ => return false
-            }
-            true
+    crate fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
+        match v {
+            Some("unwind") => *slot = Some(PanicStrategy::Unwind),
+            Some("abort") => *slot = Some(PanicStrategy::Abort),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => {
-                    match s.parse::<RelroLevel>() {
-                        Ok(level) => *slot = Some(level),
-                        _ => return false
-                    }
-                },
-                _ => return false
-            }
-            true
+    crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => match s.parse::<RelroLevel>() {
+                Ok(level) => *slot = Some(level),
+                _ => return false,
+            },
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
-            if let Some(v) = v {
-                for s in v.split(',') {
-                    *slot |= match s {
-                        "address" => SanitizerSet::ADDRESS,
-                        "leak" => SanitizerSet::LEAK,
-                        "memory" => SanitizerSet::MEMORY,
-                        "thread" => SanitizerSet::THREAD,
-                        "hwaddress" => SanitizerSet::HWADDRESS,
-                        _ => return false,
-                    }
+    crate fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
+        if let Some(v) = v {
+            for s in v.split(',') {
+                *slot |= match s {
+                    "address" => SanitizerSet::ADDRESS,
+                    "leak" => SanitizerSet::LEAK,
+                    "memory" => SanitizerSet::MEMORY,
+                    "thread" => SanitizerSet::THREAD,
+                    "hwaddress" => SanitizerSet::HWADDRESS,
+                    _ => return false,
                 }
-                true
-            } else {
-                false
             }
+            true
+        } else {
+            false
         }
+    }
 
-        fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
-            match v {
-                Some("2") | None => { *slot = 2; true }
-                Some("1") => { *slot = 1; true }
-                Some("0") => { *slot = 0; true }
-                Some(_) => false,
+    crate fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
+        match v {
+            Some("2") | None => {
+                *slot = 2;
+                true
+            }
+            Some("1") => {
+                *slot = 1;
+                true
+            }
+            Some("0") => {
+                *slot = 0;
+                true
             }
+            Some(_) => false,
         }
+    }
 
-        fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
-            match v {
-                Some("none") => *slot = Strip::None,
-                Some("debuginfo") => *slot = Strip::Debuginfo,
-                Some("symbols") => *slot = Strip::Symbols,
-                _ => return false,
-            }
-            true
+    crate fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
+        match v {
+            Some("none") => *slot = Strip::None,
+            Some("debuginfo") => *slot = Strip::Debuginfo,
+            Some("symbols") => *slot = Strip::Symbols,
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        CFGuard::Checks
-                    } else {
-                        CFGuard::Disabled
-                    };
-                    return true
-                }
+    crate fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { CFGuard::Checks } else { CFGuard::Disabled };
+                return true;
             }
-
-            *slot = match v {
-                None => CFGuard::Checks,
-                Some("checks") => CFGuard::Checks,
-                Some("nochecks") => CFGuard::NoChecks,
-                Some(_) => return false,
-            };
-            true
         }
 
-        fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
-            match v.and_then(LinkerFlavor::from_str) {
-                Some(lf) => *slote = Some(lf),
-                _ => return false,
-            }
-            true
+        *slot = match v {
+            None => CFGuard::Checks,
+            Some("checks") => CFGuard::Checks,
+            Some("nochecks") => CFGuard::NoChecks,
+            Some(_) => return false,
+        };
+        true
+    }
+
+    crate fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
+        match v.and_then(LinkerFlavor::from_str) {
+            Some(lf) => *slote = Some(lf),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
-            match v {
-                None => false,
-                Some(s) => {
-                    let parts = s.split('=').collect::<Vec<_>>();
-                    if parts.len() != 2 { return false; }
-                    let crate_name = parts[0].to_string();
-                    let fuel = parts[1].parse::<u64>();
-                    if fuel.is_err() { return false; }
-                    *slot = Some((crate_name, fuel.unwrap()));
-                    true
+    crate fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+        match v {
+            None => false,
+            Some(s) => {
+                let parts = s.split('=').collect::<Vec<_>>();
+                if parts.len() != 2 {
+                    return false;
+                }
+                let crate_name = parts[0].to_string();
+                let fuel = parts[1].parse::<u64>();
+                if fuel.is_err() {
+                    return false;
                 }
+                *slot = Some((crate_name, fuel.unwrap()));
+                true
             }
         }
+    }
 
-        fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
-            match v {
-                None => false,
-                Some(s) if s.split('=').count() <= 2 => {
-                    *slot = Some(s.to_string());
-                    true
-                }
-                _ => false,
+    crate fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
+        match v {
+            None => false,
+            Some(s) if s.split('=').count() <= 2 => {
+                *slot = Some(s.to_string());
+                true
             }
+            _ => false,
         }
+    }
 
-        fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        Some(MirSpanview::Statement)
-                    } else {
-                        None
-                    };
-                    return true
-                }
+    crate fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { Some(MirSpanview::Statement) } else { None };
+                return true;
             }
-
-            let v = match v {
-                None => {
-                    *slot = Some(MirSpanview::Statement);
-                    return true;
-                }
-                Some(v) => v,
-            };
-
-            *slot = Some(match v.trim_end_matches("s") {
-                "statement" | "stmt" => MirSpanview::Statement,
-                "terminator" | "term" => MirSpanview::Terminator,
-                "block" | "basicblock" => MirSpanview::Block,
-                _ => return false,
-            });
-            true
         }
 
-        fn parse_instrument_coverage(slot: &mut Option<InstrumentCoverage>, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        Some(InstrumentCoverage::All)
-                    } else {
-                        None
-                    };
-                    return true
-                }
+        let v = match v {
+            None => {
+                *slot = Some(MirSpanview::Statement);
+                return true;
             }
+            Some(v) => v,
+        };
+
+        *slot = Some(match v.trim_end_matches("s") {
+            "statement" | "stmt" => MirSpanview::Statement,
+            "terminator" | "term" => MirSpanview::Terminator,
+            "block" | "basicblock" => MirSpanview::Block,
+            _ => return false,
+        });
+        true
+    }
 
-            let v = match v {
-                None => {
-                    *slot = Some(InstrumentCoverage::All);
-                    return true;
-                }
-                Some(v) => v,
-            };
-
-            *slot = Some(match v {
-                "all" => InstrumentCoverage::All,
-                "except-unused-generics" | "except_unused_generics" => {
-                    InstrumentCoverage::ExceptUnusedGenerics
-                }
-                "except-unused-functions" | "except_unused_functions" => {
-                    InstrumentCoverage::ExceptUnusedFunctions
-                }
-                "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
-                _ => return false,
-            });
-            true
+    crate fn parse_instrument_coverage(
+        slot: &mut Option<InstrumentCoverage>,
+        v: Option<&str>,
+    ) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { Some(InstrumentCoverage::All) } else { None };
+                return true;
+            }
         }
 
-        fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.parse().ok(); slot.is_some() }
-                None => { *slot = NonZeroUsize::new(1); true }
+        let v = match v {
+            None => {
+                *slot = Some(InstrumentCoverage::All);
+                return true;
             }
-        }
+            Some(v) => v,
+        };
 
-        fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        LtoCli::Yes
-                    } else {
-                        LtoCli::No
-                    };
-                    return true
-                }
+        *slot = Some(match v {
+            "all" => InstrumentCoverage::All,
+            "except-unused-generics" | "except_unused_generics" => {
+                InstrumentCoverage::ExceptUnusedGenerics
             }
+            "except-unused-functions" | "except_unused_functions" => {
+                InstrumentCoverage::ExceptUnusedFunctions
+            }
+            "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
+            _ => return false,
+        });
+        true
+    }
 
-            *slot = match v {
-                None => LtoCli::NoParam,
-                Some("thin") => LtoCli::Thin,
-                Some("fat") => LtoCli::Fat,
-                Some(_) => return false,
-            };
-            true
+    crate fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = s.parse().ok();
+                slot.is_some()
+            }
+            None => {
+                *slot = NonZeroUsize::new(1);
+                true
+            }
         }
+    }
 
-        fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        LinkerPluginLto::LinkerPluginAuto
-                    } else {
-                        LinkerPluginLto::Disabled
-                    };
-                    return true
-                }
+    crate fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { LtoCli::Yes } else { LtoCli::No };
+                return true;
             }
-
-            *slot = match v {
-                None => LinkerPluginLto::LinkerPluginAuto,
-                Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
-            };
-            true
         }
 
-        fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
-            *slot = match v {
-                None => SwitchWithOptPath::Enabled(None),
-                Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
-            };
-            true
-        }
+        *slot = match v {
+            None => LtoCli::NoParam,
+            Some("thin") => LtoCli::Thin,
+            Some("fat") => LtoCli::Fat,
+            Some(_) => return false,
+        };
+        true
+    }
 
-        fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
-            match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
-                Some(mergefunc) => *slot = Some(mergefunc),
-                _ => return false,
+    crate fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() {
+                    LinkerPluginLto::LinkerPluginAuto
+                } else {
+                    LinkerPluginLto::Disabled
+                };
+                return true;
             }
-            true
         }
 
-        fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
-            match v.and_then(|s| RelocModel::from_str(s).ok()) {
-                Some(relocation_model) => *slot = Some(relocation_model),
-                None if v == Some("default") => *slot = None,
-                _ => return false,
-            }
-            true
+        *slot = match v {
+            None => LinkerPluginLto::LinkerPluginAuto,
+            Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
+        };
+        true
+    }
+
+    crate fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
+        *slot = match v {
+            None => SwitchWithOptPath::Enabled(None),
+            Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
+        };
+        true
+    }
+
+    crate fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
+        match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
+            Some(mergefunc) => *slot = Some(mergefunc),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
-            match v.and_then(|s| CodeModel::from_str(s).ok()) {
-                Some(code_model) => *slot = Some(code_model),
-                _ => return false,
-            }
-            true
+    crate fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
+        match v.and_then(|s| RelocModel::from_str(s).ok()) {
+            Some(relocation_model) => *slot = Some(relocation_model),
+            None if v == Some("default") => *slot = None,
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
-            match v.and_then(|s| TlsModel::from_str(s).ok()) {
-                Some(tls_model) => *slot = Some(tls_model),
-                _ => return false,
-            }
-            true
+    crate fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
+        match v.and_then(|s| CodeModel::from_str(s).ok()) {
+            Some(code_model) => *slot = Some(code_model),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_symbol_mangling_version(
-            slot: &mut Option<SymbolManglingVersion>,
-            v: Option<&str>,
-        ) -> bool {
-            *slot = match v {
-                Some("legacy") => Some(SymbolManglingVersion::Legacy),
-                Some("v0") => Some(SymbolManglingVersion::V0),
-                _ => return false,
-            };
-            true
+    crate fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
+        match v.and_then(|s| TlsModel::from_str(s).ok()) {
+            Some(tls_model) => *slot = Some(tls_model),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_src_file_hash(slot: &mut Option<SourceFileHashAlgorithm>, v: Option<&str>) -> bool {
-            match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
-                Some(hash_kind) => *slot = Some(hash_kind),
-                _ => return false,
-            }
-            true
+    crate fn parse_symbol_mangling_version(
+        slot: &mut Option<SymbolManglingVersion>,
+        v: Option<&str>,
+    ) -> bool {
+        *slot = match v {
+            Some("legacy") => Some(SymbolManglingVersion::Legacy),
+            Some("v0") => Some(SymbolManglingVersion::V0),
+            _ => return false,
+        };
+        true
+    }
+
+    crate fn parse_src_file_hash(
+        slot: &mut Option<SourceFileHashAlgorithm>,
+        v: Option<&str>,
+    ) -> bool {
+        match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
+            Some(hash_kind) => *slot = Some(hash_kind),
+            _ => return false,
         }
+        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
+    crate fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                if !slot.is_empty() {
+                    slot.push_str(",");
                 }
-                None => false,
+                slot.push_str(s);
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
-            match v {
-                Some("command")  => *slot = Some(WasiExecModel::Command),
-                Some("reactor") => *slot = Some(WasiExecModel::Reactor),
-                _ => return false,
-            }
-            true
+    crate fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
+        match v {
+            Some("command") => *slot = Some(WasiExecModel::Command),
+            Some("reactor") => *slot = Some(WasiExecModel::Reactor),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
-            match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
-                Some(e) => *slot = Some(e),
-                _ => return false,
-            }
-            true
+    crate fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
+        match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
+            Some(e) => *slot = Some(e),
+            _ => return false,
         }
+        true
     }
-) }
+}
 
 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
           build_codegen_options, "C", "codegen",
-          CG_OPTIONS, cg_type_desc, cgsetters,
+          CG_OPTIONS,
 
     // This list is in alphabetical order.
     //
@@ -885,7 +959,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
 
 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           build_debugging_options, "Z", "debugging",
-          DB_OPTIONS, db_type_desc, dbsetters,
+          DB_OPTIONS,
 
     // This list is in alphabetical order.
     //
@@ -1128,7 +1202,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
     self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
         parse_switch_with_opt_path, [UNTRACKED],
         "run the self profiler and output the raw event data"),
-    // keep this in sync with the event filter names in librustc_data_structures/profiling.rs
+    /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
     self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
         "specify the events recorded by the self profiler;
         for example: `-Z self-profile-events=default,query-keys`
@@ -1140,7 +1214,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "show spans for compiler debugging (expr|pat|ty)"),
     span_debug: bool = (false, parse_bool, [UNTRACKED],
         "forward proc_macro::Span's `Debug` impl to `Span`"),
-    // o/w tests have closure@path
+    /// o/w tests have closure@path
     span_free_formats: bool = (false, parse_bool, [UNTRACKED],
         "exclude spans when debug-printing compiler state (default: no)"),
     src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
@@ -1161,10 +1235,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "select processor to schedule for (`rustc --print target-cpus` for details)"),
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
-    // We default to 1 here since we want to behave like
-    // a sequential compiler for now. This'll likely be adjusted
-    // in the future. Note that -Zthreads=0 is the way to get
-    // the num_cpus behavior.
+    /// We default to 1 here since we want to behave like
+    /// a sequential compiler for now. This'll likely be adjusted
+    /// in the future. Note that -Zthreads=0 is the way to get
+    /// the num_cpus behavior.
     threads: usize = (1, parse_threads, [UNTRACKED],
         "use a thread pool with N threads"),
     time: bool = (false, parse_bool, [UNTRACKED],
@@ -1220,7 +1294,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
     // - compiler/rustc_interface/src/tests.rs
 }
 
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, PartialEq, Eq, Debug)]
 pub enum WasiExecModel {
     Command,
     Reactor,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 7bff634fb2d..e7dfc4b8c41 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -214,15 +214,6 @@ pub struct Session {
     /// drown everything else in noise.
     miri_unleashed_features: Lock<Vec<(Span, Option<Symbol>)>>,
 
-    /// Base directory containing the `src/` for the Rust standard library, and
-    /// potentially `rustc` as well, if we can can find it. Right now it's always
-    /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
-    ///
-    /// This directory is what the virtual `/rustc/$hash` is translated back to,
-    /// if Rust was built with path remapping to `/rustc/$hash` enabled
-    /// (the `rust.remap-debuginfo` option in `config.toml`).
-    pub real_rust_source_base_dir: Option<PathBuf>,
-
     /// Architecture to use for interpreting asm!.
     pub asm_arch: Option<InlineAsmArch>,
 
@@ -1390,26 +1381,6 @@ pub fn build_session(
         _ => CtfeBacktrace::Disabled,
     });
 
-    // Try to find a directory containing the Rust `src`, for more details see
-    // the doc comment on the `real_rust_source_base_dir` field.
-    let real_rust_source_base_dir = {
-        // This is the location used by the `rust-src` `rustup` component.
-        let mut candidate = sysroot.join("lib/rustlib/src/rust");
-        if let Ok(metadata) = candidate.symlink_metadata() {
-            // Replace the symlink rustbuild creates, with its destination.
-            // We could try to use `fs::canonicalize` instead, but that might
-            // produce unnecessarily verbose path.
-            if metadata.file_type().is_symlink() {
-                if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
-                    candidate = symlink_dest;
-                }
-            }
-        }
-
-        // Only use this directory if it has a file we can expect to always find.
-        if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
-    };
-
     let asm_arch =
         if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None };
 
@@ -1453,7 +1424,6 @@ pub fn build_session(
         system_library_path: OneThread::new(RefCell::new(Default::default())),
         ctfe_backtrace,
         miri_unleashed_features: Lock::new(Default::default()),
-        real_rust_source_base_dir,
         asm_arch,
         target_features: FxHashSet::default(),
         known_attrs: Lock::new(MarkedAttrs::new()),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 4be187c5208..b2dac10c83f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -634,6 +634,7 @@ symbols! {
         impl_macros,
         impl_trait_in_bindings,
         import_shadowing,
+        imported_main,
         in_band_lifetimes,
         include,
         include_bytes,
@@ -781,6 +782,7 @@ symbols! {
         no,
         no_builtins,
         no_core,
+        no_coverage,
         no_crate_inject,
         no_debug,
         no_default_passes,
@@ -852,8 +854,7 @@ symbols! {
         partial_ord,
         passes,
         pat,
-        pat2015,
-        pat2021,
+        pat_param,
         path,
         pattern_parentheses,
         phantom_data,
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index e7c9edea765..f180eea01a3 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -85,8 +85,6 @@ def_regs! {
         x15: reg = ["x15", "w15"],
         x16: reg = ["x16", "w16"],
         x17: reg = ["x17", "w17"],
-        x18: reg = ["x18", "w18"],
-        x19: reg = ["x19", "w19"],
         x20: reg = ["x20", "w20"],
         x21: reg = ["x21", "w21"],
         x22: reg = ["x22", "w22"],
@@ -96,7 +94,7 @@ def_regs! {
         x26: reg = ["x26", "w26"],
         x27: reg = ["x27", "w27"],
         x28: reg = ["x28", "w28"],
-        x30: reg = ["x30", "w30", "lr"],
+        x30: reg = ["x30", "w30", "lr", "wlr"],
         v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"],
         v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"],
         v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"],
@@ -129,7 +127,11 @@ def_regs! {
         v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"],
         v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"],
         v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"],
-        #error = ["x29", "fp"] =>
+        #error = ["x18", "w18"] =>
+            "x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
+        #error = ["x19", "w19"] =>
+            "x19 is used internally by LLVM and cannot be used as an operand for inline asm",
+        #error = ["x29", "w29", "fp", "wfp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["sp", "wsp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index a7a708fe7de..4c323fc35d6 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -98,7 +98,6 @@ def_regs! {
         r5: reg, reg_thumb = ["r5", "v2"],
         r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
         r8: reg = ["r8", "v5"],
-        r9: reg = ["r9", "v6", "rfp"],
         r10: reg = ["r10", "sl"],
         r11: reg = ["r11", "fp"] % frame_pointer_r11,
         r12: reg = ["r12", "ip"],
@@ -185,6 +184,8 @@ def_regs! {
         q15: qreg = ["q15"],
         #error = ["r6", "v3"] =>
             "r6 is used internally by LLVM and cannot be used as an operand for inline asm",
+        #error = ["r9", "v6", "rfp"] =>
+            "r9 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r13", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["r15", "pc"] =>
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
index d41941d0b4c..74afddb69dc 100644
--- a/compiler/rustc_target/src/asm/hexagon.rs
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -60,7 +60,6 @@ def_regs! {
         r16: reg = ["r16"],
         r17: reg = ["r17"],
         r18: reg = ["r18"],
-        r19: reg = ["r19"],
         r20: reg = ["r20"],
         r21: reg = ["r21"],
         r22: reg = ["r22"],
@@ -70,6 +69,8 @@ def_regs! {
         r26: reg = ["r26"],
         r27: reg = ["r27"],
         r28: reg = ["r28"],
+        #error = ["r19"] =>
+            "r19 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r29", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["r30", "fr"] =>
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index 185d6ac8246..e276a9175f9 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -66,7 +66,6 @@ def_regs! {
         x5: reg = ["x5", "t0"],
         x6: reg = ["x6", "t1"],
         x7: reg = ["x7", "t2"],
-        x9: reg = ["x9", "s1"],
         x10: reg = ["x10", "a0"],
         x11: reg = ["x11", "a1"],
         x12: reg = ["x12", "a2"],
@@ -121,6 +120,8 @@ def_regs! {
         f29: freg = ["f29", "ft9"],
         f30: freg = ["f30", "ft10"],
         f31: freg = ["f31", "ft11"],
+        #error = ["x9", "s1"] =>
+            "s1 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["x8", "s0", "fp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["x2", "sp"] =>
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 90660dad4c2..48f83ca7cd4 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -152,13 +152,41 @@ fn high_byte(
     }
 }
 
+fn rbx_reserved(
+    arch: InlineAsmArch,
+    _has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
+) -> Result<(), &'static str> {
+    match arch {
+        InlineAsmArch::X86 => Ok(()),
+        InlineAsmArch::X86_64 => {
+            Err("rbx is used internally by LLVM and cannot be used as an operand for inline asm")
+        }
+        _ => unreachable!(),
+    }
+}
+
+fn esi_reserved(
+    arch: InlineAsmArch,
+    _has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
+) -> Result<(), &'static str> {
+    match arch {
+        InlineAsmArch::X86 => {
+            Err("esi is used internally by LLVM and cannot be used as an operand for inline asm")
+        }
+        InlineAsmArch::X86_64 => Ok(()),
+        _ => unreachable!(),
+    }
+}
+
 def_regs! {
     X86 X86InlineAsmReg X86InlineAsmRegClass {
         ax: reg, reg_abcd = ["ax", "eax", "rax"],
-        bx: reg, reg_abcd = ["bx", "ebx", "rbx"],
+        bx: reg, reg_abcd = ["bx", "ebx", "rbx"] % rbx_reserved,
         cx: reg, reg_abcd = ["cx", "ecx", "rcx"],
         dx: reg, reg_abcd = ["dx", "edx", "rdx"],
-        si: reg = ["si", "esi", "rsi"],
+        si: reg = ["si", "esi", "rsi"] % esi_reserved,
         di: reg = ["di", "edi", "rdi"],
         r8: reg = ["r8", "r8w", "r8d"] % x86_64_only,
         r9: reg = ["r9", "r9w", "r9d"] % x86_64_only,
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index cfaf020175b..f5d7be4537b 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -12,7 +12,8 @@ pub fn target() -> Target {
         arch: "x86".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 2d3310c7582..06d71db4af2 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.eliminate_frame_pointer = false;
 
     // Clang automatically chooses a more specific target based on
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index 18cd8847abd..19d7b3c95cf 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -11,7 +11,8 @@ pub fn target() -> Target {
     // http://developer.android.com/ndk/guides/abis.html#x86
     base.cpu = "pentiumpro".to_string();
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-linux-android".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
index a26cabdc90a..d8e37e72371 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
@@ -7,7 +7,8 @@ pub fn target() -> Target {
     let pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default();
     pre_link_args.push("-m32".to_string());
     pre_link_args.push("-Wl,-znotext".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-freebsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
index 5fba4e3f14a..e4c01db5439 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-haiku".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
index 633e8da0ccb..165505ee731 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index 8bcd261e4df..228976779f0 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-Wl,-melf_i386".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
     // implementation, apparently relies on frame pointers existing... somehow.
diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
index e020264ad7a..989e3fb1adf 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-netbsdelf".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
index 86448cb9115..7ff79961375 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-fuse-ld=lld".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-openbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
index e596eca86b0..c7963dbde77 100644
--- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index d17d729c289..64f47b4aa9b 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -5,7 +5,8 @@ pub fn opts() -> TargetOptions {
         env: "gnu".to_string(),
         disable_redzone: true,
         panic_strategy: PanicStrategy::Abort,
-        stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+        // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+        stack_probes: StackProbeType::Call,
         eliminate_frame_pointer: false,
         linker_is_gnu: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index c82359223da..dc7597fe7b2 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -10,7 +10,8 @@ pub fn target() -> Target {
         vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
     );
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
     // Clang automatically chooses a more specific target based on
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index 6feeeac451b..adb87718589 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -11,7 +11,8 @@ pub fn target() -> Target {
         arch: "x86_64".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index a6e066213e7..c228e42ef30 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -11,7 +11,8 @@ pub fn target() -> Target {
         arch: "x86_64".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index f8c47168da8..e3a5de4cbd1 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -10,7 +10,8 @@ pub fn target() -> Target {
         arch: "x86_64".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
index 99acc7c207b..aa65ebe1f9d 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -4,7 +4,8 @@ pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers = SanitizerSet::ADDRESS;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
index 0945a9f5c59..9065283b731 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -7,7 +7,8 @@ pub fn target() -> Target {
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-linux-android".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
index 75eece74ff9..b78e43d4fe9 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.vendor = "pc".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
index 63e524fa8a9..2fa53470f74 100644
--- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.vendor = "sun".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
index 295f9c837c3..d69830f0a3f 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-dragonfly".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
index ca3556fc48e..b5fc15f5e04 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
index 963d4fdb12f..fcd96ddd61b 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     // This option is required to build executables on Haiku x86_64
     base.position_independent_executables = true;
 
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
index 31164f8408d..1ef24b6eb36 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.features = "+rdrnd,+rdseed".to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index 9569e98ed59..085079e06e5 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers =
         SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
 
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
index 5f87534fe95..7b77ad668cd 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mx32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.has_elf_tls = false;
     // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
     // breaks code gen. See LLVM bug 36743
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
index 1e2e5766a31..5ad243aa407 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.static_position_independent_executables = true;
     base.supported_sanitizers =
         SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
index 54e7ceee82e..0269c7afe55 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs
index a357def190b..28d9801b78c 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs
@@ -7,7 +7,8 @@ pub fn target() -> Target {
     base.features =
         "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
             .to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-none-elf".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
index 530e63966aa..4eb3f34a036 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-openbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
index 934f8de8ecc..b8269ecae20 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-redox".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
index f9fa9d93843..f9f775084fb 100644
--- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.disable_redzone = true;
 
     Target {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index ac5ec24eeee..d5e1bd3f9ea 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -132,6 +132,14 @@ fn object_safety_violations_for_trait(
             .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
     );
 
+    violations.extend(
+        tcx.associated_items(trait_def_id)
+            .in_definition_order()
+            .filter(|item| item.kind == ty::AssocKind::Type)
+            .filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
+            .map(|item| ObjectSafetyViolation::GAT(item.ident.name, item.ident.span)),
+    );
+
     debug!(
         "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
         trait_def_id, violations
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 31685a012ca..e338a21b603 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -462,12 +462,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         for assoc_type in assoc_types {
             if !tcx.generics_of(assoc_type).params.is_empty() {
-                // FIXME(generic_associated_types) generate placeholders to
-                // extend the trait substs.
-                tcx.sess.span_fatal(
+                tcx.sess.delay_span_bug(
                     obligation.cause.span,
-                    "generic associated types in trait objects are not supported yet",
+                    "GATs in trait object shouldn't have been considered",
                 );
+                return Err(SelectionError::Unimplemented);
             }
             // This maybe belongs in wf, but that can't (doesn't) handle
             // higher-ranked things.
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 38e5ce6fd83..144c7281b67 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,5 +1,4 @@
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_middle::hir::map as hir_map;
@@ -400,10 +399,6 @@ fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
     tcx.crate_name
 }
 
-fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
-    tcx.index_hir(crate_num).crate_hash
-}
-
 fn instance_def_size_estimate<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance_def: ty::InstanceDef<'tcx>,
@@ -551,7 +546,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         trait_of_item,
         crate_disambiguator,
         original_crate_name,
-        crate_hash,
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index a3804e468da..077375c7c3b 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -278,9 +278,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 // another. This is an error. However, if we already know that
                                 // the arguments don't match up with the parameters, we won't issue
                                 // an additional error, as the user already knows what's wrong.
-                                if arg_count.correct.is_ok()
-                                    && arg_count.explicit_late_bound == ExplicitLateBound::No
-                                {
+                                if arg_count.correct.is_ok() {
                                     // We're going to iterate over the parameters to sort them out, and
                                     // show that order to the user as a possible order for the parameters
                                     let mut param_types_present = defs
@@ -462,7 +460,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 }
 
                 if silent {
-                    return false;
+                    return true;
                 }
 
                 if provided > expected_max {
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 72c633dcb20..92d7ea26003 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -6,7 +6,7 @@ use super::*;
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorReported};
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
@@ -16,15 +16,14 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::layout::MAX_SIMD_LANES;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt};
-use rustc_session::config::EntryFnType;
+use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
 use rustc_session::lint::builtin::UNINHABITED_STATIC;
 use rustc_span::symbol::sym;
 use rustc_span::{self, MultiSpan, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCauseCode};
 use rustc_ty_utils::representability::{self, Representability};
 
 use std::iter;
@@ -326,29 +325,6 @@ pub(super) fn check_fn<'a, 'tcx>(
     }
     fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
 
-    // Check that the main return type implements the termination trait.
-    if let Some(term_id) = tcx.lang_items().termination() {
-        if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
-            let main_id = hir.local_def_id_to_hir_id(def_id);
-            if main_id == fn_id {
-                let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
-                let trait_ref = ty::TraitRef::new(term_id, substs);
-                let return_ty_span = decl.output.span();
-                let cause = traits::ObligationCause::new(
-                    return_ty_span,
-                    fn_id,
-                    ObligationCauseCode::MainFunctionType,
-                );
-
-                inherited.register_predicate(traits::Obligation::new(
-                    cause,
-                    param_env,
-                    trait_ref.without_const().to_predicate(tcx),
-                ));
-            }
-        }
-    }
-
     // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
         if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index a50f8e1c655..1959fe75e8e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1282,6 +1282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let mut infer_args_for_err = FxHashSet::default();
 
+        let mut explicit_late_bound = ExplicitLateBound::No;
         for &PathSeg(def_id, index) in &path_segs {
             let seg = &segments[index];
             let generics = tcx.generics_of(def_id);
@@ -1290,17 +1291,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // parameter internally, but we don't allow users to specify the
             // parameter's value explicitly, so we have to do some error-
             // checking here.
-            if let GenericArgCountResult {
-                correct: Err(GenericArgCountMismatch { reported: Some(_), .. }),
-                ..
-            } = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
+            let arg_count = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
                 tcx,
                 span,
                 def_id,
                 &generics,
                 seg,
                 IsMethodCall::No,
-            ) {
+            );
+
+            if let ExplicitLateBound::Yes = arg_count.explicit_late_bound {
+                explicit_late_bound = ExplicitLateBound::Yes;
+            }
+
+            if let Err(GenericArgCountMismatch { reported: Some(_), .. }) = arg_count.correct {
                 infer_args_for_err.insert(index);
                 self.set_tainted_by_errors(); // See issue #53251.
             }
@@ -1357,7 +1361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ty = tcx.type_of(def_id);
 
         let arg_count = GenericArgCountResult {
-            explicit_late_bound: ExplicitLateBound::No,
+            explicit_late_bound,
             correct: if infer_args_for_err.is_empty() {
                 Ok(())
             } else {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index cb4257e0534..cb7589318d2 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -116,7 +116,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::WithConstness;
 use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType};
 use rustc_session::config;
 use rustc_session::parse::feature_err;
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 26871d6f028..d25dd9a6e83 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -315,17 +315,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                         ),
                     )
                 } else {
-                    tcx.sess
-                        .struct_span_err(
-                            hir_ty.span,
-                            &format!(
-                                "{} is forbidden as the type of a const generic parameter",
-                                unsupported_type
-                            ),
-                        )
-                        .note("the only supported types are integers, `bool` and `char`")
-                        .help("more complex types are supported with `#![feature(const_generics)]`")
-                        .emit()
+                    let mut err = tcx.sess.struct_span_err(
+                        hir_ty.span,
+                        &format!(
+                            "{} is forbidden as the type of a const generic parameter",
+                            unsupported_type
+                        ),
+                    );
+                    err.note("the only supported types are integers, `bool` and `char`");
+                    if tcx.sess.is_nightly_build() {
+                        err.help(
+                            "more complex types are supported with `#![feature(const_generics)]`",
+                        );
+                    }
+                    err.emit()
                 }
             };
 
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 46ee8245432..190c9d35934 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2661,6 +2661,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     let mut inline_span = None;
     let mut link_ordinal_span = None;
     let mut no_sanitize_span = None;
+    let mut no_coverage_feature_enabled = false;
+    let mut no_coverage_attr = None;
     for attr in attrs.iter() {
         if tcx.sess.check_name(attr, sym::cold) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
@@ -2724,6 +2726,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
         } else if tcx.sess.check_name(attr, sym::no_mangle) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+        } else if attr.has_name(sym::feature) {
+            if let Some(list) = attr.meta_item_list() {
+                if list.iter().any(|nested_meta_item| nested_meta_item.has_name(sym::no_coverage)) {
+                    tcx.sess.mark_attr_used(attr);
+                    no_coverage_feature_enabled = true;
+                }
+            }
+        } else if tcx.sess.check_name(attr, sym::no_coverage) {
+            no_coverage_attr = Some(attr);
         } else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
         } else if tcx.sess.check_name(attr, sym::used) {
@@ -2934,6 +2945,23 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         }
     }
 
+    if let Some(no_coverage_attr) = no_coverage_attr {
+        if tcx.sess.features_untracked().no_coverage || no_coverage_feature_enabled {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE
+        } else {
+            let mut err = feature_err(
+                &tcx.sess.parse_sess,
+                sym::no_coverage,
+                no_coverage_attr.span,
+                "the `#[no_coverage]` attribute is an experimental feature",
+            );
+            if tcx.sess.parse_sess.unstable_features.is_nightly_build() {
+                err.help("or, alternatively, add `#[feature(no_coverage)]` to the function");
+            }
+            err.emit();
+        }
+    }
+
     codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
         if !attr.has_name(sym::inline) {
             return ia;
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 532ee00daf8..f1749412794 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -763,7 +763,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                         PlaceBase::Local(*var_hir_id)
                     };
                     let place_with_id = PlaceWithHirId::new(
-                        capture_info.path_expr_id.unwrap_or(closure_expr.hir_id),
+                        capture_info.path_expr_id.unwrap_or(
+                            capture_info.capture_kind_expr_id.unwrap_or(closure_expr.hir_id),
+                        ),
                         place.base_ty,
                         place_base,
                         place.projections.clone(),
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 190744fe6f1..4e07e52347a 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -97,8 +97,8 @@ mod variance;
 
 use rustc_errors::{struct_span_err, ErrorReported};
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
-use rustc_hir::Node;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::{Node, CRATE_HIR_ID};
 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::middle;
@@ -110,7 +110,7 @@ use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
+    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
 };
 
 use std::iter;
@@ -164,106 +164,203 @@ fn require_same_types<'tcx>(
     })
 }
 
-fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) {
-    let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id);
+fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
+    let main_fnsig = tcx.fn_sig(main_def_id);
     let main_span = tcx.def_span(main_def_id);
-    let main_t = tcx.type_of(main_def_id);
-    match main_t.kind() {
-        ty::FnDef(..) => {
-            if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
-                if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
-                    let mut error = false;
-                    if !generics.params.is_empty() {
-                        let msg = "`main` function is not allowed to have generic \
-                                   parameters"
-                            .to_owned();
-                        let label = "`main` cannot have generic parameters".to_string();
-                        struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
-                            .span_label(generics.span, label)
-                            .emit();
-                        error = true;
-                    }
-                    if let Some(sp) = generics.where_clause.span() {
-                        struct_span_err!(
-                            tcx.sess,
-                            sp,
-                            E0646,
-                            "`main` function is not allowed to have a `where` clause"
-                        )
-                        .span_label(sp, "`main` cannot have a `where` clause")
-                        .emit();
-                        error = true;
-                    }
-                    if let hir::IsAsync::Async = sig.header.asyncness {
-                        let span = tcx.sess.source_map().guess_head_span(it.span);
-                        struct_span_err!(
-                            tcx.sess,
-                            span,
-                            E0752,
-                            "`main` function is not allowed to be `async`"
-                        )
-                        .span_label(span, "`main` function is not allowed to be `async`")
-                        .emit();
-                        error = true;
-                    }
 
-                    let attrs = tcx.hir().attrs(main_id);
-                    for attr in attrs {
-                        if tcx.sess.check_name(attr, sym::track_caller) {
-                            tcx.sess
-                                .struct_span_err(
-                                    attr.span,
-                                    "`main` function is not allowed to be `#[track_caller]`",
-                                )
-                                .span_label(
-                                    main_span,
-                                    "`main` function is not allowed to be `#[track_caller]`",
-                                )
-                                .emit();
-                            error = true;
-                        }
-                    }
+    fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId {
+        if let Some(local_def_id) = def_id.as_local() {
+            let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
+            let hir_type = tcx.type_of(local_def_id);
+            if !matches!(hir_type.kind(), ty::FnDef(..)) {
+                span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
+            }
+            hir_id
+        } else {
+            CRATE_HIR_ID
+        }
+    }
 
-                    if error {
-                        return;
-                    }
-                }
+    fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
+        }
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
+                let generics_param_span =
+                    if !generics.params.is_empty() { Some(generics.span) } else { None };
+                generics_param_span
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
             }
+        }
+    }
 
-            let actual = tcx.fn_sig(main_def_id);
-            let expected_return_type = if tcx.lang_items().termination().is_some() {
-                // we take the return type of the given main function, the real check is done
-                // in `check_fn`
-                actual.output()
-            } else {
-                // standard () main return type
-                ty::Binder::dummy(tcx.mk_unit())
-            };
-
-            let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| {
-                tcx.mk_fn_sig(
-                    iter::empty(),
-                    expected_return_type,
-                    false,
-                    hir::Unsafety::Normal,
-                    Abi::Rust,
-                )
-            }));
+    fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
+        }
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
+                generics.where_clause.span()
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
+            }
+        }
+    }
 
-            require_same_types(
-                tcx,
-                &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
-                se_ty,
-                tcx.mk_fn_ptr(actual),
-            );
+    fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
         }
-        _ => {
-            span_bug!(main_span, "main has a non-function type: found `{}`", main_t);
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { span: item_span, .. })) => {
+                Some(tcx.sess.source_map().guess_head_span(*item_span))
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
+            }
         }
     }
-}
 
-fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) {
+    fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
+        }
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => {
+                Some(fn_sig.decl.output.span())
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
+            }
+        }
+    }
+
+    let mut error = false;
+    let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span);
+    let main_fn_generics = tcx.generics_of(main_def_id);
+    let main_fn_predicates = tcx.predicates_of(main_def_id);
+    if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
+        let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
+        let msg = "`main` function is not allowed to have generic \
+            parameters";
+        let mut diag =
+            struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg);
+        if let Some(generics_param_span) = generics_param_span {
+            let label = "`main` cannot have generic parameters".to_string();
+            diag.span_label(generics_param_span, label);
+        }
+        diag.emit();
+        error = true;
+    } else if !main_fn_predicates.predicates.is_empty() {
+        // generics may bring in implicit predicates, so we skip this check if generics is present.
+        let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            generics_where_clauses_span.unwrap_or(main_span),
+            E0646,
+            "`main` function is not allowed to have a `where` clause"
+        );
+        if let Some(generics_where_clauses_span) = generics_where_clauses_span {
+            diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause");
+        }
+        diag.emit();
+        error = true;
+    }
+
+    let main_asyncness = tcx.asyncness(main_def_id);
+    if let hir::IsAsync::Async = main_asyncness {
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            main_span,
+            E0752,
+            "`main` function is not allowed to be `async`"
+        );
+        let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
+        if let Some(asyncness_span) = asyncness_span {
+            diag.span_label(asyncness_span, "`main` function is not allowed to be `async`");
+        }
+        diag.emit();
+        error = true;
+    }
+
+    for attr in tcx.get_attrs(main_def_id) {
+        if tcx.sess.check_name(attr, sym::track_caller) {
+            tcx.sess
+                .struct_span_err(
+                    attr.span,
+                    "`main` function is not allowed to be `#[track_caller]`",
+                )
+                .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`")
+                .emit();
+            error = true;
+        }
+    }
+
+    if error {
+        return;
+    }
+
+    let expected_return_type;
+    if let Some(term_id) = tcx.lang_items().termination() {
+        let return_ty = main_fnsig.output();
+        let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
+        if !return_ty.bound_vars().is_empty() {
+            let msg = "`main` function return type is not allowed to have generic \
+                    parameters"
+                .to_owned();
+            struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit();
+            error = true;
+        }
+        let return_ty = return_ty.skip_binder();
+        tcx.infer_ctxt().enter(|infcx| {
+            let cause = traits::ObligationCause::new(
+                return_ty_span,
+                main_diagnostics_hir_id,
+                ObligationCauseCode::MainFunctionType,
+            );
+            let mut fulfillment_cx = traits::FulfillmentContext::new();
+            fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause);
+            if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
+                infcx.report_fulfillment_errors(&err, None, false);
+                error = true;
+            }
+        });
+        // now we can take the return type of the given main function
+        expected_return_type = main_fnsig.output();
+    } else {
+        // standard () main return type
+        expected_return_type = ty::Binder::dummy(tcx.mk_unit());
+    }
+
+    if error {
+        return;
+    }
+
+    let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| {
+        tcx.mk_fn_sig(iter::empty(), expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
+    }));
+
+    require_same_types(
+        tcx,
+        &ObligationCause::new(
+            main_span,
+            main_diagnostics_hir_id,
+            ObligationCauseCode::MainFunctionType,
+        ),
+        se_ty,
+        tcx.mk_fn_ptr(main_fnsig),
+    );
+}
+fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
+    let start_def_id = start_def_id.expect_local();
     let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
     let start_span = tcx.def_span(start_def_id);
     let start_t = tcx.type_of(start_def_id);
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index f330a1bb3dc..af403496e38 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -89,7 +89,7 @@ impl<K, V> LeafNode<K, V> {
 
 /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
 /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
-/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the
+/// `InternalNode` can be directly cast to a pointer to the underlying `LeafNode` portion of the
 /// node, allowing code to act on leaf and internal nodes generically without having to even check
 /// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`.
 #[repr(C)]
@@ -408,7 +408,7 @@ impl<K, V> NodeRef<marker::Dying, K, V, marker::LeafOrInternal> {
 }
 
 impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// Temporarily takes out another, mutable reference to the same node. Beware, as
+    /// Temporarily takes out another mutable reference to the same node. Beware, as
     /// this method is very dangerous, doubly so since it may not immediately appear
     /// dangerous.
     ///
@@ -759,7 +759,7 @@ impl<BorrowType, K, V, NodeType, HandleType> PartialEq
 impl<BorrowType, K, V, NodeType, HandleType>
     Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
 {
-    /// Temporarily takes out another, immutable handle on the same location.
+    /// Temporarily takes out another immutable handle on the same location.
     pub fn reborrow(&self) -> Handle<NodeRef<marker::Immut<'_>, K, V, NodeType>, HandleType> {
         // We can't use Handle::new_kv or Handle::new_edge because we don't know our type
         Handle { node: self.node.reborrow(), idx: self.idx, _marker: PhantomData }
@@ -767,7 +767,7 @@ impl<BorrowType, K, V, NodeType, HandleType>
 }
 
 impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
-    /// Temporarily takes out another, mutable handle on the same location. Beware, as
+    /// Temporarily takes out another mutable handle on the same location. Beware, as
     /// this method is very dangerous, doubly so since it may not immediately appear
     /// dangerous.
     ///
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 3a5dcec668f..15308a4469b 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -76,7 +76,6 @@
 #![cfg_attr(test, feature(test))]
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(allocator_api)]
-#![feature(vec_extend_from_within)]
 #![feature(array_chunks)]
 #![feature(array_methods)]
 #![feature(array_windows)]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index e459442dfcf..85c9446689e 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2124,8 +2124,6 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// ## Examples
     ///
     /// ```
-    /// #![feature(vec_extend_from_within)]
-    ///
     /// let mut vec = vec![0, 1, 2, 3, 4];
     ///
     /// vec.extend_from_within(2..);
@@ -2137,7 +2135,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// vec.extend_from_within(4..8);
     /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]);
     /// ```
-    #[unstable(feature = "vec_extend_from_within", issue = "81656")]
+    #[stable(feature = "vec_extend_from_within", since = "1.53.0")]
     pub fn extend_from_within<R>(&mut self, src: R)
     where
         R: RangeBounds<usize>,
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 7e1194cc4aa..25a83a0b014 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -20,7 +20,6 @@
 #![feature(vecdeque_binary_search)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
-#![feature(vec_extend_from_within)]
 #![feature(vec_spare_capacity)]
 #![feature(string_remove_matches)]
 
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index cdb6006b1b3..0a3e5789e8b 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -274,6 +274,8 @@ pub trait Eq: PartialEq<Self> {
     //
     // This should never be implemented by hand.
     #[doc(hidden)]
+    #[cfg_attr(not(bootstrap), feature(no_coverage))]
+    #[cfg_attr(not(bootstrap), no_coverage)]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn assert_receiver_is_total_eq(&self) {}
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index f7aec736449..a0b65399da2 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -128,7 +128,7 @@ pub fn spin_loop() {
         #[cfg(target_arch = "aarch64")]
         {
             // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
-            unsafe { crate::arch::aarch64::__yield() };
+            unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };
         }
         #[cfg(target_arch = "arm")]
         {
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 7977d599ae7..da9e5fde7cc 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -2133,7 +2133,6 @@ pub trait Iterator {
     /// ```
     ///
     /// [`reduce()`]: Iterator::reduce
-    #[doc(alias = "reduce")]
     #[doc(alias = "inject")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 5f1f7d8cac4..c7f58f36154 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -21,7 +21,8 @@
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(nll)]
 #![feature(staged_api)]
-#![feature(const_fn)]
+#![cfg_attr(bootstrap, feature(const_fn))]
+#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
 #![feature(const_fn_fn_ptr_basics)]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 116a37249e3..821e7d4cfe7 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -124,6 +124,10 @@ pub fn vars() -> Vars {
 /// variables at the time of this invocation. Modifications to environment
 /// variables afterwards will not be reflected in the returned iterator.
 ///
+/// Note that the returned iterator will not check if the environment variables
+/// are valid Unicode. If you want to panic on invalid UTF-8,
+/// use the [`vars`] function instead.
+///
 /// # Examples
 ///
 /// ```
@@ -180,8 +184,9 @@ impl fmt::Debug for VarsOs {
 ///
 /// # Errors
 ///
-/// * Environment variable is not present
-/// * Environment variable is not valid unicode
+/// Errors if the environment variable is not present.
+/// Errors if the environment variable is not valid Unicode. If this is not desired, consider using
+/// [`var_os`].
 ///
 /// # Panics
 ///
@@ -221,6 +226,10 @@ fn _var(key: &OsStr) -> Result<String, VarError> {
 /// `'='` or the NUL character `'\0'`, or when the value contains the NUL
 /// character.
 ///
+/// Note that the method will not check if the environment variable
+/// is valid Unicode. If you want to have an error on invalid UTF-8,
+/// use the [`var`] function instead.
+///
 /// # Examples
 ///
 /// ```
@@ -752,7 +761,7 @@ pub fn args() -> Args {
 /// does on macOS and Windows.
 ///
 /// Note that the returned iterator will not check if the arguments to the
-/// process are valid Unicode. To ensure UTF-8 validity,
+/// process are valid Unicode. If you want to panic on invalid UTF-8,
 /// use the [`args`] function instead.
 ///
 /// # Examples
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index ecaab670349..ea4b2866017 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -71,7 +71,6 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 /// [`&str`]: str
 /// [`CStr`]: crate::ffi::CStr
 /// [conversions]: super#conversions
-#[derive(Clone)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "OsString")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
@@ -421,6 +420,19 @@ impl Default for OsString {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for OsString {
+    #[inline]
+    fn clone(&self) -> Self {
+        OsString { inner: self.inner.clone() }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, source: &Self) {
+        self.inner.clone_from(&source.inner)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Debug for OsString {
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Debug::fmt(&**self, formatter)
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index f4020a42879..ed0987064e8 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1065,7 +1065,6 @@ impl FusedIterator for Ancestors<'_> {}
 /// ```
 ///
 /// Which method works best depends on what kind of situation you're in.
-#[derive(Clone)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME:
@@ -1406,6 +1405,19 @@ impl PathBuf {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for PathBuf {
+    #[inline]
+    fn clone(&self) -> Self {
+        PathBuf { inner: self.inner.clone() }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, source: &Self) {
+        self.inner.clone_from(&source.inner)
+    }
+}
+
 #[stable(feature = "box_from_path", since = "1.17.0")]
 impl From<&Path> for Box<Path> {
     fn from(path: &Path) -> Box<Path> {
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index c37111f665c..cd6b0b2d7ee 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -553,8 +553,10 @@ mod prim_pointer {}
 /// # Editions
 ///
 /// Prior to Rust 1.53, arrays did not implement `IntoIterator` by value, so the method call
-/// `array.into_iter()` auto-referenced into a slice iterator. That behavior is preserved in the
-/// 2015 and 2018 editions of Rust for compatability, ignoring `IntoIterator` by value.
+/// `array.into_iter()` auto-referenced into a slice iterator. Right now, the old behavior
+/// is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring
+/// `IntoIterator` by value. In the future, the behavior on the 2015 and 2018 edition
+/// might be made consistent to the behavior of later editions.
 ///
 #[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
 #[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
@@ -601,6 +603,49 @@ mod prim_pointer {}
 /// }
 /// ```
 ///
+/// Future language versions might start treating the `array.into_iter()`
+/// syntax on editions 2015 and 2018 the same as on edition 2021. So code using
+/// those older editions should still be written with this change in mind, to
+/// prevent breakage in the future. The safest way to accomplish this is to
+/// avoid the `into_iter` syntax on those editions. If an edition update is not
+/// viable/desired, there are multiple alternatives:
+/// * use `iter`, equivalent to the old behavior, creating references
+/// * use [`array::IntoIter`], equivalent to the post-2021 behavior (Rust 1.51+)
+/// * replace `for ... in array.into_iter() {` with `for ... in array {`,
+///   equivalent to the post-2021 behavior (Rust 1.53+)
+///
+#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
+#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
+/// use std::array::IntoIter;
+///
+/// let array: [i32; 3] = [0; 3];
+///
+/// // This iterates by reference:
+/// for item in array.iter() {
+///     let x: &i32 = item;
+///     println!("{}", x);
+/// }
+///
+/// // This iterates by value:
+/// for item in IntoIter::new(array) {
+///     let x: i32 = item;
+///     println!("{}", x);
+/// }
+///
+/// // This iterates by value:
+/// for item in array {
+///     let x: i32 = item;
+///     println!("{}", x);
+/// }
+///
+/// // IntoIter can also start a chain.
+/// // This iterates by value:
+/// for item in IntoIter::new(array).enumerate() {
+///     let (i, x): (usize, i32) = item;
+///     println!("array[{}] = {}", i, x);
+/// }
+/// ```
+///
 /// [slice]: prim@slice
 /// [`Debug`]: fmt::Debug
 /// [`Hash`]: hash::Hash
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 2615bea6592..773ab18b2ce 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -3,9 +3,7 @@ mod tests;
 
 use crate::cell::UnsafeCell;
 use crate::fmt;
-use crate::mem;
 use crate::ops::{Deref, DerefMut};
-use crate::ptr;
 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
 use crate::sys_common::mutex as sys;
 
@@ -376,23 +374,8 @@ impl<T: ?Sized> Mutex<T> {
     where
         T: Sized,
     {
-        // We know statically that there are no outstanding references to
-        // `self` so there's no need to lock the inner mutex.
-        //
-        // To get the inner value, we'd like to call `data.into_inner()`,
-        // but because `Mutex` impl-s `Drop`, we can't move out of it, so
-        // we'll have to destructure it manually instead.
-        unsafe {
-            // Like `let Mutex { inner, poison, data } = self`.
-            let (inner, poison, data) = {
-                let Mutex { ref inner, ref poison, ref data } = self;
-                (ptr::read(inner), ptr::read(poison), ptr::read(data))
-            };
-            mem::forget(self);
-            drop(inner);
-
-            poison::map_result(poison.borrow(), |_| data.into_inner())
-        }
+        let data = self.data.into_inner();
+        poison::map_result(self.poison.borrow(), |_| data)
     }
 
     /// Returns a mutable reference to the underlying data.
diff --git a/library/std/src/sys/hermit/cmath.rs b/library/std/src/sys/hermit/cmath.rs
deleted file mode 100644
index 304cf906b2a..00000000000
--- a/library/std/src/sys/hermit/cmath.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// These symbols are all defined in `compiler-builtins`
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 3364d215776..0c49a6fb6de 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -20,6 +20,7 @@ use crate::os::raw::c_char;
 
 pub mod alloc;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
diff --git a/library/std/src/sys/sgx/cmath.rs b/library/std/src/sys/sgx/cmath.rs
deleted file mode 100644
index b89238f1da8..00000000000
--- a/library/std/src/sys/sgx/cmath.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-#![cfg(not(test))]
-
-// These symbols are all defined in `compiler-builtins`
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-}
diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/sys/sgx/ext/arch.rs
index 730db34e733..b0170e67446 100644
--- a/library/std/src/sys/sgx/ext/arch.rs
+++ b/library/std/src/sys/sgx/ext/arch.rs
@@ -32,9 +32,12 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32>
         let error;
 
         asm!(
+            // rbx is reserved by LLVM
+            "xchg {0}, rbx",
             "enclu",
+            "mov rbx, {0}",
+            inout(reg) request => _,
             inlateout("eax") ENCLU_EGETKEY => error,
-            in("rbx") request,
             in("rcx") out.as_mut_ptr(),
             options(nostack),
         );
@@ -60,9 +63,12 @@ pub fn ereport(
         let mut report = MaybeUninit::uninit();
 
         asm!(
+            // rbx is reserved by LLVM
+            "xchg {0}, rbx",
             "enclu",
+            "mov rbx, {0}",
+            inout(reg) targetinfo => _,
             in("eax") ENCLU_EREPORT,
-            in("rbx") targetinfo,
             in("rcx") reportdata,
             in("rdx") report.as_mut_ptr(),
             options(preserves_flags, nostack),
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index 059d6cb5ba1..bf3bd57e982 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -13,6 +13,7 @@ mod waitqueue;
 
 pub mod alloc;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
diff --git a/library/std/src/sys/unix/cmath.rs b/library/std/src/sys/unix/cmath.rs
index f327b69fc75..2bf80d7a4cb 100644
--- a/library/std/src/sys/unix/cmath.rs
+++ b/library/std/src/sys/unix/cmath.rs
@@ -1,32 +1,33 @@
 #![cfg(not(test))]
 
-use libc::{c_double, c_float};
+// These symbols are all defined by `libm`,
+// or by `compiler-builtins` on unsupported platforms.
 
 extern "C" {
-    pub fn acos(n: c_double) -> c_double;
-    pub fn acosf(n: c_float) -> c_float;
-    pub fn asin(n: c_double) -> c_double;
-    pub fn asinf(n: c_float) -> c_float;
-    pub fn atan(n: c_double) -> c_double;
-    pub fn atan2(a: c_double, b: c_double) -> c_double;
-    pub fn atan2f(a: c_float, b: c_float) -> c_float;
-    pub fn atanf(n: c_float) -> c_float;
-    pub fn cbrt(n: c_double) -> c_double;
-    pub fn cbrtf(n: c_float) -> c_float;
-    pub fn cosh(n: c_double) -> c_double;
-    pub fn coshf(n: c_float) -> c_float;
-    pub fn expm1(n: c_double) -> c_double;
-    pub fn expm1f(n: c_float) -> c_float;
-    pub fn fdim(a: c_double, b: c_double) -> c_double;
-    pub fn fdimf(a: c_float, b: c_float) -> c_float;
-    pub fn hypot(x: c_double, y: c_double) -> c_double;
-    pub fn hypotf(x: c_float, y: c_float) -> c_float;
-    pub fn log1p(n: c_double) -> c_double;
-    pub fn log1pf(n: c_float) -> c_float;
-    pub fn sinh(n: c_double) -> c_double;
-    pub fn sinhf(n: c_float) -> c_float;
-    pub fn tan(n: c_double) -> c_double;
-    pub fn tanf(n: c_float) -> c_float;
-    pub fn tanh(n: c_double) -> c_double;
-    pub fn tanhf(n: c_float) -> c_float;
+    pub fn acos(n: f64) -> f64;
+    pub fn acosf(n: f32) -> f32;
+    pub fn asin(n: f64) -> f64;
+    pub fn asinf(n: f32) -> f32;
+    pub fn atan(n: f64) -> f64;
+    pub fn atan2(a: f64, b: f64) -> f64;
+    pub fn atan2f(a: f32, b: f32) -> f32;
+    pub fn atanf(n: f32) -> f32;
+    pub fn cbrt(n: f64) -> f64;
+    pub fn cbrtf(n: f32) -> f32;
+    pub fn cosh(n: f64) -> f64;
+    pub fn coshf(n: f32) -> f32;
+    pub fn expm1(n: f64) -> f64;
+    pub fn expm1f(n: f32) -> f32;
+    pub fn fdim(a: f64, b: f64) -> f64;
+    pub fn fdimf(a: f32, b: f32) -> f32;
+    pub fn hypot(x: f64, y: f64) -> f64;
+    pub fn hypotf(x: f32, y: f32) -> f32;
+    pub fn log1p(n: f64) -> f64;
+    pub fn log1pf(n: f32) -> f32;
+    pub fn sinh(n: f64) -> f64;
+    pub fn sinhf(n: f32) -> f32;
+    pub fn tan(n: f64) -> f64;
+    pub fn tanf(n: f32) -> f32;
+    pub fn tanh(n: f64) -> f64;
+    pub fn tanhf(n: f32) -> f32;
 }
diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs
index 9a982a4acd9..9cf51be2836 100644
--- a/library/std/src/sys/unix/ext/fs.rs
+++ b/library/std/src/sys/unix/ext/fs.rs
@@ -884,3 +884,29 @@ impl DirBuilderExt for fs::DirBuilder {
         self
     }
 }
+
+/// Change the root directory of the current process to the specified path.
+///
+/// This typically requires privileges, such as root or a specific capability.
+///
+/// This does not change the current working directory; you should call
+/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chroot)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::chroot("/sandbox")?;
+///     std::env::set_current_dir("/")?;
+///     // continue working in sandbox
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chroot", issue = "84715")]
+#[cfg(not(target_os = "fuchsia"))]
+pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
+    sys::fs::chroot(dir.as_ref())
+}
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 16a7f727696..45bae25a0c3 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1328,3 +1328,10 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     })?;
     Ok(bytes_copied as u64)
 }
+
+#[cfg(not(target_os = "fuchsia"))]
+pub fn chroot(dir: &Path) -> io::Result<()> {
+    let dir = cstr(dir)?;
+    cvt(unsafe { libc::chroot(dir.as_ptr()) })?;
+    Ok(())
+}
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index a0ee69c2f72..6c4fbaf2734 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -11,6 +11,7 @@ pub mod weak;
 pub mod alloc;
 pub mod android;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
diff --git a/library/std/src/sys/unsupported/cmath.rs b/library/std/src/sys/unsupported/cmath.rs
deleted file mode 100644
index 304cf906b2a..00000000000
--- a/library/std/src/sys/unsupported/cmath.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// These symbols are all defined in `compiler-builtins`
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-}
diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs
index 32ca68ef15b..3ef4c6b8a8f 100644
--- a/library/std/src/sys/unsupported/mod.rs
+++ b/library/std/src/sys/unsupported/mod.rs
@@ -2,6 +2,7 @@
 
 pub mod alloc;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index 2584d35b6ef..37f74fcc052 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -20,7 +20,7 @@ use crate::mem;
 #[path = "../unix/alloc.rs"]
 pub mod alloc;
 pub mod args;
-#[path = "../unsupported/cmath.rs"]
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 #[path = "../unsupported/condvar.rs"]
 pub mod condvar;
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index 8705910c73a..afcc5ca9286 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -18,7 +18,7 @@
 
 pub mod alloc;
 pub mod args;
-#[path = "../unsupported/cmath.rs"]
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod env;
 #[path = "../unsupported/fs.rs"]
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 30bbfdd0dd1..a5799606142 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -19,9 +19,9 @@ use crate::sys::c;
 use crate::sys::cvt;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
-use crate::sys::mutex::Mutex;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::stdio;
+use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::sys_common::AsInner;
 
@@ -94,10 +94,6 @@ pub struct StdioPipes {
     pub stderr: Option<AnonPipe>,
 }
 
-struct DropGuard<'a> {
-    lock: &'a Mutex,
-}
-
 impl Command {
     pub fn new(program: &OsStr) -> Command {
         Command {
@@ -209,8 +205,9 @@ impl Command {
         //
         // For more information, msdn also has an article about this race:
         // http://support.microsoft.com/kb/315939
-        static CREATE_PROCESS_LOCK: Mutex = Mutex::new();
-        let _guard = DropGuard::new(&CREATE_PROCESS_LOCK);
+        static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
+
+        let _guard = unsafe { CREATE_PROCESS_LOCK.lock() };
 
         let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
         let null = Stdio::Null;
@@ -259,23 +256,6 @@ impl fmt::Debug for Command {
     }
 }
 
-impl<'a> DropGuard<'a> {
-    fn new(lock: &'a Mutex) -> DropGuard<'a> {
-        unsafe {
-            lock.lock();
-            DropGuard { lock }
-        }
-    }
-}
-
-impl<'a> Drop for DropGuard<'a> {
-    fn drop(&mut self) {
-        unsafe {
-            self.lock.unlock();
-        }
-    }
-}
-
 impl Stdio {
     fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
         match *self {
diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs
index 302c5197407..32705c432fa 100644
--- a/library/std/src/sys_common/os_str_bytes.rs
+++ b/library/std/src/sys_common/os_str_bytes.rs
@@ -14,7 +14,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 use core::str::lossy::Utf8Lossy;
 
-#[derive(Clone, Hash)]
+#[derive(Hash)]
 pub(crate) struct Buf {
     pub inner: Vec<u8>,
 }
@@ -53,6 +53,18 @@ impl fmt::Display for Buf {
     }
 }
 
+impl Clone for Buf {
+    #[inline]
+    fn clone(&self) -> Self {
+        Buf { inner: self.inner.clone() }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, source: &Self) {
+        self.inner.clone_from(&source.inner)
+    }
+}
+
 impl IntoInner<Vec<u8>> for Buf {
     fn into_inner(self) -> Vec<u8> {
         self.inner
diff --git a/rustfmt.toml b/rustfmt.toml
index af807aa6f73..480b19a5e93 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -7,6 +7,8 @@ merge_derives = false
 # tidy only checks files which are not ignored, each entry follows gitignore style
 ignore = [
     "/build/",
+    "/*-build/",
+    "/build-*/",
     "/vendor/",
 
     # tests for now are not formatted, as they are sometimes pretty-printing constrained
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 4111420e474..356d9f5d1ff 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -414,10 +414,13 @@ class RustBuild(object):
             filename = "rustc-{}-{}{}".format(rustc_channel, self.build,
                                               tarball_suffix)
             self._download_component_helper(filename, "rustc", tarball_suffix, stage0)
-            filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
-                                              tarball_suffix)
-            self._download_component_helper(filename, "cargo", tarball_suffix)
-            if not stage0:
+            # download-rustc doesn't need its own cargo, it can just use beta's.
+            if stage0:
+                filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
+                                                tarball_suffix)
+                self._download_component_helper(filename, "cargo", tarball_suffix)
+                self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
+            else:
                 filename = "rustc-dev-{}-{}{}".format(rustc_channel, self.build, tarball_suffix)
                 self._download_component_helper(
                     filename, "rustc-dev", tarball_suffix, stage0
@@ -425,7 +428,6 @@ class RustBuild(object):
 
             self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root))
             self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root))
-            self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
             lib_dir = "{}/lib".format(bin_root)
             for lib in os.listdir(lib_dir):
                 if lib.endswith(".so"):
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 38901a35296..62a3a87eeb8 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1627,6 +1627,11 @@ impl Cargo {
     pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
         builder.add_rustc_lib_path(compiler, &mut self.command);
     }
+
+    pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
+        self.command.current_dir(dir);
+        self
+    }
 }
 
 impl From<Cargo> for Command {
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 6626fead774..9b76c8b9a2d 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -280,7 +280,7 @@ impl Step for CodegenBackend {
 }
 
 macro_rules! tool_check_step {
-    ($name:ident, $path:expr, $source_type:expr) => {
+    ($name:ident, $path:literal, $($alias:literal, )* $source_type:path) => {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub target: TargetSelection,
@@ -292,7 +292,7 @@ macro_rules! tool_check_step {
             const DEFAULT: bool = true;
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-                run.path($path)
+                run.paths(&[ $path, $($alias),* ])
             }
 
             fn make_run(run: RunConfig<'_>) {
@@ -321,11 +321,9 @@ macro_rules! tool_check_step {
                 }
 
                 // Enable internal lints for clippy and rustdoc
-                // NOTE: this intentionally doesn't enable lints for any other tools,
-                // see https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
-                if $path == "src/tools/rustdoc" || $path == "src/tools/clippy" {
-                    cargo.rustflag("-Zunstable-options");
-                }
+                // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
+                // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
+                cargo.rustflag("-Zunstable-options");
 
                 builder.info(&format!(
                     "Checking stage{} {} artifacts ({} -> {})",
@@ -363,7 +361,7 @@ macro_rules! tool_check_step {
     };
 }
 
-tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree);
+tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
 // Clippy is a hybrid. It is an external tool, but uses a git subtree instead
 // of a submodule. Since the SourceType only drives the deny-warnings
 // behavior, treat it as in-tree so that any new warnings in clippy will be
diff --git a/src/bootstrap/defaults/config.codegen.toml b/src/bootstrap/defaults/config.codegen.toml
index a9505922ca7..011ff6821b7 100644
--- a/src/bootstrap/defaults/config.codegen.toml
+++ b/src/bootstrap/defaults/config.codegen.toml
@@ -11,3 +11,5 @@ assertions = true
 debug-logging = true
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
+# Print backtrace on internal compiler errors during bootstrap
+backtrace-on-ice = true
diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml
index 883bfead64e..4d689d117bc 100644
--- a/src/bootstrap/defaults/config.compiler.toml
+++ b/src/bootstrap/defaults/config.compiler.toml
@@ -6,6 +6,8 @@
 debug-logging = true
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
+# Print backtrace on internal compiler errors during bootstrap
+backtrace-on-ice = true
 
 [llvm]
 # Will download LLVM from CI if available on your platform.
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index b9d7ecf8c0e..965d1162145 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -632,6 +632,26 @@ impl Step for Clippy {
 
         cargo.add_rustc_lib_path(builder, compiler);
 
+        if builder.try_run(&mut cargo.into()) {
+            // The tests succeeded; nothing to do.
+            return;
+        }
+
+        if !builder.config.cmd.bless() {
+            std::process::exit(1);
+        }
+
+        let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run");
+        cargo.arg("-p").arg("clippy_dev");
+        // clippy_dev gets confused if it can't find `clippy/Cargo.toml`
+        cargo.current_dir(&builder.src.join("src").join("tools").join("clippy"));
+        if builder.config.rust_optimize {
+            cargo.env("PROFILE", "release");
+        } else {
+            cargo.env("PROFILE", "debug");
+        }
+        cargo.arg("--");
+        cargo.arg("bless");
         builder.run(&mut cargo.into());
     }
 }
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index e85f4628fb0..4f2426648fd 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -392,7 +392,10 @@ impl ErrorIndex {
         let compiler = builder.compiler(builder.top_stage.saturating_sub(1), builder.config.build);
         let mut cmd = Command::new(builder.ensure(ErrorIndex { compiler }));
         add_dylib_path(
-            vec![PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))],
+            vec![
+                PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host)),
+                PathBuf::from(builder.rustc_libdir(compiler)),
+            ],
             &mut cmd,
         );
         cmd
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
index 08f07eb8284..ea70771a570 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
@@ -38,6 +38,7 @@ ENV HOSTS=x86_64-unknown-linux-musl
 ENV RUST_CONFIGURE_ARGS \
       --musl-root-x86_64=/usr/local/x86_64-linux-musl \
       --enable-extended \
+      --enable-sanitizers \
       --enable-profiler \
       --enable-lld \
       --set target.x86_64-unknown-linux-musl.crt-static=false \
diff --git a/src/doc/book b/src/doc/book
-Subproject b54090a99ec7c4b46a5203a9c927fdbc311bb1f
+Subproject 50dd06cb71beb27fdc0eebade5509cdcc1f821e
diff --git a/src/doc/reference b/src/doc/reference
-Subproject e1abb17cd94cd5a8a374b48e1bc8134a2208ed4
+Subproject d23f9da8469617e6c81121d9fd123443df70595
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject c80f0b09fc15b9251825343be910c08531938ab
+Subproject e0a721f5202e6d9bec0aff99f10e44480c0da9e
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject a9bd2bbf31e4f92b5d3d8e80b22839d0cc7a202
+Subproject e72b43a64925ce053dc7830e21c1a57ba00499b
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 7f57d476aa9..b3c67b84da6 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -6,43 +6,38 @@
     }
 </style>
 
-Support for different platforms are organized into three tiers, each with a
-different set of guarantees. For more information on the policies for targets
-at each tier, see the [Target Tier Policy](target-tier-policy.md).
+Support for different platforms ("targets") are organized into three tiers,
+each with a different set of guarantees. For more information on the policies
+for targets at each tier, see the [Target Tier Policy](target-tier-policy.md).
 
-Platforms are identified by their "target triple" which is the string to
-inform the compiler what kind of output should be produced. The columns in the
-tables below have the following meanings:
+Targets are identified by their "target triple" which is the string to inform
+the compiler what kind of output should be produced.
 
-* std:
-    * ✓ indicates the full standard library is available.
-    * \* indicates the target only supports [`no_std`] development.
-    * ? indicates the standard library support is unknown or a work-in-progress.
-* host: A ✓ indicates that `rustc` and `cargo` can run on the host platform.
+## Tier 1 with Host Tools
 
-[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
-
-## Tier 1
+Tier 1 targets can be thought of as "guaranteed to work". The Rust project
+builds official binary releases for each tier 1 target, and automated testing
+ensures that each tier 1 target builds and passes tests after each change.
 
-Tier 1 platforms can be thought of as "guaranteed to work".
-Specifically they will each satisfy the following requirements:
+Tier 1 targets with host tools additionally support running tools like `rustc`
+and `cargo` natively on the target, and automated testing ensures that tests
+pass for the host tools as well. This allows the target to be used as a
+development platform, not just a compilation target. For the full requirements,
+see [Tier 1 with Host Tools](target-tier-policy.md#tier-1-with-host-tools) in
+the Target Tier Policy.
 
-* Official binary releases are provided for the platform.
-* Automated testing is set up to run tests for the platform.
-* Landing changes to the `rust-lang/rust` repository's master branch is gated
-  on tests passing.
-* Documentation for how to use and how to build the platform is available.
+All tier 1 targets with host tools support the full standard library.
 
-target | std | host | notes
--------|-----|------|-------
-`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
-`i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
-`i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
-`i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
-`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+)
-`x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+)
-`x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
-`x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
+target | notes
+-------|-------
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
+`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+)
+`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+)
+`i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+)
+`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+)
+`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+)
+`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
 
 [^missing-stack-probes]: Stack probes support is missing on
   `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
@@ -50,105 +45,153 @@ target | std | host | notes
 
 [77071]: https://github.com/rust-lang/rust/issues/77071
 
+## Tier 1
+
+Tier 1 targets can be thought of as "guaranteed to work". The Rust project
+builds official binary releases for each tier 1 target, and automated testing
+ensures that each tier 1 target builds and passes tests after each change. For
+the full requirements, see [Tier 1 target
+policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy.
+
+At this time, all Tier 1 targets are [Tier 1 with Host
+Tools](#tier-1-with-host-tools).
+
+## Tier 2 with Host Tools
+
+Tier 2 targets can be thought of as "guaranteed to build". The Rust project
+builds official binary releases for each tier 2 target, and automated builds
+ensure that each tier 2 target builds after each change. Automated tests are
+not always run so it's not guaranteed to produce a working build, but tier 2
+targets often work to quite a good degree and patches are always welcome!
+
+Tier 2 targets with host tools additionally support running tools like `rustc`
+and `cargo` natively on the target, and automated builds ensure that the host
+tools build as well. This allows the target to be used as a development
+platform, not just a compilation target. For the full requirements, see [Tier 2
+with Host Tools](target-tier-policy.md#tier-2-with-host-tools) in the Target
+Tier Policy.
+
+All tier 2 targets with host tools support the full standard library.
+
+target | notes
+-------|-------
+`aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+)
+`aarch64-pc-windows-msvc` | ARM64 Windows MSVC
+`aarch64-unknown-linux-musl` | ARM64 Linux with MUSL
+`arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17)
+`arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`armv7-unknown-linux-gnueabihf` | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23)
+`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
+`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
+`riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29)
+`s390x-unknown-linux-gnu` | S390x Linux (kernel 2.6.32, glibc 2.11)
+`x86_64-unknown-freebsd` | 64-bit FreeBSD
+`x86_64-unknown-illumos` | illumos
+`x86_64-unknown-linux-musl` | 64-bit Linux with MUSL
+`x86_64-unknown-netbsd` | NetBSD/amd64
+
 ## Tier 2
 
-Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
-are not run so it's not guaranteed to produce a working build, but platforms
-often work to quite a good degree and patches are always welcome!
-Specifically, these platforms are required to have each of the following:
+Tier 2 targets can be thought of as "guaranteed to build". The Rust project
+builds official binary releases for each tier 2 target, and automated builds
+ensure that each tier 2 target builds after each change. Automated tests are
+not always run so it's not guaranteed to produce a working build, but tier 2
+targets often work to quite a good degree and patches are always welcome! For
+the full requirements, see [Tier 2 target
+policy](target-tier-policy.md#tier-2-target-policy) in the Target Tier Policy.
 
-* Official binary releases are provided for the platform.
-* Automated building is set up, but may not be running tests.
-* Landing changes to the `rust-lang/rust` repository's master branch is gated on
-    platforms **building**. For some platforms only the standard library is
-    compiled, but for others `rustc` and `cargo` are too.
+The `std` column in the table below has the following meanings:
 
-target | std | host | notes
--------|-----|------|-------
-`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+)
-`aarch64-apple-ios` | ✓ |  | ARM64 iOS
-`aarch64-fuchsia` | ✓ |  | ARM64 Fuchsia
-`aarch64-linux-android` | ✓ |  | ARM64 Android
-`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
-`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
-`aarch64-unknown-none` | * |  | Bare ARM64, hardfloat
-`aarch64-unknown-none-softfloat` | * |  | Bare ARM64, softfloat
-`arm-linux-androideabi` | ✓ |  | ARMv7 Android
-`arm-unknown-linux-gnueabi` | ✓ | ✓ | ARMv6 Linux (kernel 3.2, glibc 2.17)
-`arm-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
-`arm-unknown-linux-musleabi` | ✓ |  | ARMv6 Linux with MUSL
-`arm-unknown-linux-musleabihf` | ✓ |  | ARMv6 Linux with MUSL, hardfloat
-`armebv7r-none-eabi` | * |  | Bare ARMv7-R, Big Endian
-`armebv7r-none-eabihf` | * |  | Bare ARMv7-R, Big Endian, hardfloat
-`armv5te-unknown-linux-gnueabi` | ✓ |  | ARMv5TE Linux (kernel 4.4, glibc 2.23)
-`armv5te-unknown-linux-musleabi` | ✓ |  | ARMv5TE Linux with MUSL
-`armv7-linux-androideabi` | ✓ |  | ARMv7a Android
-`armv7a-none-eabi` | * |  | Bare ARMv7-A
-`armv7r-none-eabi` | * |  | Bare ARMv7-R
-`armv7r-none-eabihf` | * |  | Bare ARMv7-R, hardfloat
-`armv7-unknown-linux-gnueabi` | ✓ |   | ARMv7 Linux (kernel 4.15, glibc 2.27)
-`armv7-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
-`armv7-unknown-linux-musleabi` | ✓ |   | ARMv7 Linux, MUSL
-`armv7-unknown-linux-musleabihf` | ✓ |  | ARMv7 Linux with MUSL
-`asmjs-unknown-emscripten` | ✓ |  | asm.js via Emscripten
-`i586-pc-windows-msvc` | ✓ |  | 32-bit Windows w/o SSE
-`i586-unknown-linux-gnu` | ✓ |  | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
-`i586-unknown-linux-musl` | ✓ |  | 32-bit Linux w/o SSE, MUSL
-`i686-linux-android` | ✓ |  | 32-bit x86 Android
-`i686-unknown-freebsd` | ✓ |  | 32-bit FreeBSD
-`i686-unknown-linux-musl` | ✓ |  | 32-bit Linux with MUSL
-`mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
-`mips-unknown-linux-musl` | ✓ |  | MIPS Linux with MUSL
-`mips64-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64-unknown-linux-muslabi64` | ✓ |  | MIPS64 Linux, n64 ABI, MUSL
-`mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64el-unknown-linux-muslabi64` | ✓ |  | MIPS64 (LE) Linux, n64 ABI, MUSL
-`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
-`mipsel-unknown-linux-musl` | ✓ |  | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` | ✓ |  | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
-`powerpc-unknown-linux-gnu` | ✓ | ✓ | PowerPC Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64-unknown-linux-gnu` | ✓ | ✓ | PPC64 Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64le-unknown-linux-gnu` | ✓ | ✓ | PPC64LE Linux (kernel 3.10, glibc 2.17)
-`riscv32i-unknown-none-elf` | * |  | Bare RISC-V (RV32I ISA)
-`riscv32imac-unknown-none-elf` | * |  | Bare RISC-V (RV32IMAC ISA)
-`riscv32imc-unknown-none-elf` | * |  | Bare RISC-V (RV32IMC ISA)
-`riscv64gc-unknown-linux-gnu` | ✓ | ✓ | RISC-V Linux (kernel 4.20, glibc 2.29)
-`riscv64gc-unknown-none-elf` | * |  | Bare RISC-V (RV64IMAFDC ISA)
-`riscv64imac-unknown-none-elf` | * |  | Bare RISC-V (RV64IMAC ISA)
-`s390x-unknown-linux-gnu` | ✓ | ✓ | S390x Linux (kernel 2.6.32, glibc 2.11)
-`sparc64-unknown-linux-gnu` | ✓ |  | SPARC Linux (kernel 4.4, glibc 2.23)
-`sparcv9-sun-solaris` | ✓ |  | SPARC Solaris 10/11, illumos
-`thumbv6m-none-eabi` | * |  | Bare Cortex-M0, M0+, M1
-`thumbv7em-none-eabi` | * |  | Bare Cortex-M4, M7
-`thumbv7em-none-eabihf` | * |  | Bare Cortex-M4F, M7F, FPU, hardfloat
-`thumbv7m-none-eabi` | * |  | Bare Cortex-M3
-`thumbv7neon-linux-androideabi` | ✓ |  | Thumb2-mode ARMv7a Android with NEON
-`thumbv7neon-unknown-linux-gnueabihf` | ✓ |  | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
-`thumbv8m.base-none-eabi` | * |  | ARMv8-M Baseline
-`thumbv8m.main-none-eabi` | * |  | ARMv8-M Mainline
-`thumbv8m.main-none-eabihf` | * |  | ARMv8-M Mainline, hardfloat
-`wasm32-unknown-emscripten` | ✓ |  | WebAssembly via Emscripten
-`wasm32-unknown-unknown` | ✓ |  | WebAssembly
-`wasm32-wasi` | ✓ |  | WebAssembly with WASI
-`x86_64-apple-ios` | ✓ |  | 64-bit x86 iOS
-`x86_64-fortanix-unknown-sgx` | ✓ |  | [Fortanix ABI] for 64-bit Intel SGX
-`x86_64-fuchsia` | ✓ |  | 64-bit Fuchsia
-`x86_64-linux-android` | ✓ |  | 64-bit x86 Android
-`x86_64-pc-solaris` | ✓ |  | 64-bit Solaris 10/11, illumos
-`x86_64-unknown-freebsd` | ✓ | ✓ | 64-bit FreeBSD
-`x86_64-unknown-illumos` | ✓ | ✓ | illumos
-`x86_64-unknown-linux-gnux32` | ✓ |  | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
-`x86_64-unknown-linux-musl` | ✓ | ✓ | 64-bit Linux with MUSL
-`x86_64-unknown-netbsd` | ✓ | ✓ | NetBSD/amd64
-`x86_64-unknown-redox` | ✓ |  | Redox OS
+* ✓ indicates the full standard library is available.
+* \* indicates the target only supports [`no_std`] development.
+
+[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+
+target | std | notes
+-------|-----|-------
+`aarch64-apple-ios` | ✓ | ARM64 iOS
+`aarch64-fuchsia` | ✓ | ARM64 Fuchsia
+`aarch64-linux-android` | ✓ | ARM64 Android
+`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
+`aarch64-unknown-none` | * | Bare ARM64, hardfloat
+`arm-linux-androideabi` | ✓ | ARMv7 Android
+`arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
+`arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
+`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian
+`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat
+`armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23)
+`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
+`armv7-linux-androideabi` | ✓ | ARMv7a Android
+`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27)
+`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux, MUSL
+`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL
+`armv7a-none-eabi` | * | Bare ARMv7-A
+`armv7r-none-eabi` | * | Bare ARMv7-R
+`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
+`asmjs-unknown-emscripten` | ✓ | asm.js via Emscripten
+`i586-pc-windows-msvc` | ✓ | 32-bit Windows w/o SSE
+`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
+`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL
+`i686-linux-android` | ✓ | 32-bit x86 Android
+`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD
+`i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL
+`mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL
+`mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
+`mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
+`mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
+`nvptx64-nvidia-cuda` | ✓ | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
+`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
+`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
+`riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
+`riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
+`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
+`sparcv9-sun-solaris` | ✓ | SPARC Solaris 10/11, illumos
+`thumbv6m-none-eabi` | * | Bare Cortex-M0, M0+, M1
+`thumbv7em-none-eabi` | * | Bare Cortex-M4, M7
+`thumbv7em-none-eabihf` | * | Bare Cortex-M4F, M7F, FPU, hardfloat
+`thumbv7m-none-eabi` | * | Bare Cortex-M3
+`thumbv7neon-linux-androideabi` | ✓ | Thumb2-mode ARMv7a Android with NEON
+`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
+`thumbv8m.base-none-eabi` | * | ARMv8-M Baseline
+`thumbv8m.main-none-eabi` | * | ARMv8-M Mainline
+`thumbv8m.main-none-eabihf` | * | ARMv8-M Mainline, hardfloat
+`wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
+`wasm32-unknown-unknown` | ✓ | WebAssembly
+`wasm32-wasi` | ✓ | WebAssembly with WASI
+`x86_64-apple-ios` | ✓ | 64-bit x86 iOS
+`x86_64-fortanix-unknown-sgx` | ✓ | [Fortanix ABI] for 64-bit Intel SGX
+`x86_64-fuchsia` | ✓ | 64-bit Fuchsia
+`x86_64-linux-android` | ✓ | 64-bit x86 Android
+`x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos
+`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
+`x86_64-unknown-redox` | ✓ | Redox OS
 
 [Fortanix ABI]: https://edp.fortanix.com/
 
 ## Tier 3
 
-Tier 3 platforms are those which the Rust codebase has support for, but which
-are not built or tested automatically, and may not work. Official builds are
-not available.
+Tier 3 targets are those which the Rust codebase has support for, but which the
+Rust project does not build or test automatically, so they may or may not work.
+Official builds are not available. For the full requirements, see [Tier 3
+target policy](target-tier-policy.md#tier-3-target-policy) in the Target Tier
+Policy.
+
+The `std` column in the table below has the following meanings:
+
+* ✓ indicates the full standard library is available.
+* \* indicates the target only supports [`no_std`] development.
+* ? indicates the standard library support is unknown or a work-in-progress.
+
+[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+
+The `host` column indicates whether the codebase includes support for building
+host tools.
 
 target | std | host | notes
 -------|-----|------|-------
@@ -163,8 +206,8 @@ target | std | host | notes
 `aarch64-unknown-redox` | ? |  | ARM64 Redox OS
 `aarch64-uwp-windows-msvc` | ? |  |
 `aarch64-wrs-vxworks` | ? |  |
-`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
+`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 `armv4t-unknown-linux-gnueabi` | ? |  |
 `armv5te-unknown-linux-uclibceabi` | ? |  | ARMv5TE Linux with uClibc
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
@@ -175,22 +218,22 @@ target | std | host | notes
 `armv7-wrs-vxworks-eabihf` | ? |  |
 `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
 `armv7s-apple-ios` | ✓ |  |
-`avr-unknown-gnu-atmega328` | ✗ |  | AVR. Requires `-Z build-std=core`
+`avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `hexagon-unknown-linux-musl` | ? |  |
 `i386-apple-ios` | ✓ |  | 32-bit x86 iOS
 `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
-`i686-unknown-uefi` | * |  | 32-bit UEFI
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
 `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
 `i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD
+`i686-unknown-uefi` | * |  | 32-bit UEFI
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
 `i686-wrs-vxworks` | ? |  |
 `mips-unknown-linux-uclibc` | ✓ |  | MIPS Linux with uClibc
+`mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 `mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
 `mipsel-unknown-none` | * |  | Bare MIPS (LE) softfloat
-`mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 `mipsisa32r6-unknown-linux-gnu` | ? |  |
 `mipsisa32r6el-unknown-linux-gnu` | ? |  |
 `mipsisa64r6-unknown-linux-gnuabi64` | ? |  |
@@ -200,34 +243,34 @@ target | std | host | notes
 `powerpc-unknown-linux-musl` | ? |  |
 `powerpc-unknown-netbsd` | ✓ | ✓ |
 `powerpc-unknown-openbsd` | ? |  |
-`powerpc-wrs-vxworks` | ? |  |
 `powerpc-wrs-vxworks-spe` | ? |  |
+`powerpc-wrs-vxworks` | ? |  |
 `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
 `powerpc64-unknown-linux-musl` | ? |  |
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
-`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
+`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 2.6.32, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
 `sparc64-unknown-openbsd` | ? |  |
+`thumbv4t-none-eabi` | * |  | ARMv4T T32
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7a Linux with NEON, MUSL
-`thumbv4t-none-eabi` | * |  | ARMv4T T32
 `wasm64-unknown-unknown` | * |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
 `x86_64-apple-tvos` | * | | x86 64-bit tvOS
-`x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
-`x86_64-sun-solaris` | ? |  | Deprecated target for 64-bit Solaris 10/11, illumos
 `x86_64-pc-windows-msvc` | ✓ |  | 64-bit Windows XP support
+`x86_64-sun-solaris` | ? |  | Deprecated target for 64-bit Solaris 10/11, illumos
 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
 `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
 `x86_64-unknown-hermit` | ? |  |
-`x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
 `x86_64-unknown-l4re-uclibc` | ? |  |
+`x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
+`x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
 `x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
 `x86_64-unknown-uefi` | * |  | 64-bit UEFI
 `x86_64-uwp-windows-gnu` | ✓ |  |
diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md
index 463f56099f6..a2cb0351916 100644
--- a/src/doc/rustc/src/target-tier-policy.md
+++ b/src/doc/rustc/src/target-tier-policy.md
@@ -1,5 +1,16 @@
 # Target Tier Policy
 
+## Table of Contents
+
+* [General](#general)
+* [Tier 3 target policy](#tier-3-target-policy)
+* [Tier 2 target policy](#tier-2-target-policy)
+  * [Tier 2 with host tools](#tier-2-with-host-tools)
+* [Tier 1 target policy](#tier-1-target-policy)
+  * [Tier 1 with host tools](#tier-1-with-host-tools)
+
+## General
+
 Rust provides three tiers of target support:
 
 - Rust provides no guarantees about tier 3 targets; they exist in the codebase,
diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md
index 0d05b80e211..f0ecb6871b1 100644
--- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md
+++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md
@@ -200,7 +200,7 @@ running 31 tests
 test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
 ```
 
-You should have one ore more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
+You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
 
 ```shell
 $ cargo profdata -- merge \
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index 4f9033cedc3..fa96e47ee03 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -535,20 +535,20 @@ Here is the list of currently supported register classes:
 
 | Architecture | Register class | Registers | LLVM constraint code |
 | ------------ | -------------- | --------- | -------------------- |
-| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |
+| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `bp`, `r[8-15]` (x86-64 only) | `r` |
 | x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
 | x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
-| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b` | `q` |
+| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `bpl`, `r[8-15]b` | `q` |
 | x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
 | x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
 | x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
 | x86 | `kreg` | `k[1-7]` | `Yk` |
-| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |
+| AArch64 | `reg` | `x[0-30]` | `r` |
 | AArch64 | `vreg` | `v[0-31]` | `w` |
 | AArch64 | `vreg_low16` | `v[0-15]` | `x` |
-| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` |
+| ARM | `reg` | `r[0-12]`, `r14` | `r` |
 | ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
-| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |
+| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
 | ARM | `sreg` | `s[0-31]` | `t` |
 | ARM | `sreg_low16` | `s[0-15]` | `x` |
 | ARM | `dreg` | `d[0-31]` | `w` |
@@ -573,9 +573,7 @@ Here is the list of currently supported register classes:
 >
 > Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
 >
-> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
->
-> Note #5: WebAssembly doesn't have registers, so named registers are not supported.
+> Note #4: WebAssembly doesn't have registers, so named registers are not supported.
 
 Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
 
@@ -677,13 +675,14 @@ Some registers cannot be used for input or output operands:
 | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
 | All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. |
 | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
-| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |
+| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `r19` (Hexagon), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
 | x86 | `k0` | This is a constant zero register which can't be modified. |
 | x86 | `ip` | This is the program counter, not a real register. |
 | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
 | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
 | AArch64 | `xzr` | This is a constant zero register which can't be modified. |
 | ARM | `pc` | This is the program counter, not a real register. |
+| ARM | `r9` | This is a reserved register on some ARM targets. |
 | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
 | MIPS | `$1` or `$at` | Reserved for assembler. |
 | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
@@ -693,9 +692,10 @@ Some registers cannot be used for input or output operands:
 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
 | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
 
-In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are:
-- The frame pointer on all architectures.
-- `r6` on ARM.
+In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are the frame pointer and base pointer
+- The frame pointer and LLVM base pointer on all architectures.
+- `r9` on ARM.
+- `x18` on AArch64.
 
 ## Template modifiers
 
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 92eb6214f79..dbdf2e4bbb0 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -118,7 +118,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 span: Span::dummy(),
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
-                provided_trait_methods: Default::default(),
                 trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
                 for_: ty.clean(self.cx),
                 items: Vec::new(),
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 3a14a1d23f2..f5c4034a61d 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -92,12 +92,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                 }
 
                 self.cx.generated_synthetics.insert((ty, trait_def_id));
-                let provided_trait_methods = self
-                    .cx
-                    .tcx
-                    .provided_trait_methods(trait_def_id)
-                    .map(|meth| meth.ident.name)
-                    .collect();
 
                 impls.push(Item {
                     name: None,
@@ -112,7 +106,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             self.cx.tcx.explicit_predicates_of(impl_def_id),
                         )
                             .clean(self.cx),
-                        provided_trait_methods,
                         // FIXME(eddyb) compute both `trait_` and `for_` from
                         // the post-inference `trait_ref`, as it's more accurate.
                         trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 3e89c1ac4c5..5dd9f3f1ebd 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -414,16 +414,10 @@ crate fn build_impl(
         record_extern_trait(cx, trait_did);
     }
 
-    let provided = trait_
-        .def_id()
-        .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
-        .unwrap_or_default();
-
-    debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
-
     let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
     debug!("merged_attrs={:?}", merged_attrs);
 
+    debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
     ret.push(clean::Item::from_def_id_and_attrs_and_parts(
         did,
         None,
@@ -431,7 +425,6 @@ crate fn build_impl(
             span: clean::types::rustc_span(did, cx.tcx),
             unsafety: hir::Unsafety::Normal,
             generics,
-            provided_trait_methods: provided,
             trait_,
             for_,
             items: trait_items,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 12f03d00a65..78b76b05018 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1931,11 +1931,6 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
         build_deref_target_impls(cx, &items, &mut ret);
     }
 
-    let provided: FxHashSet<Symbol> = trait_
-        .def_id()
-        .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
-        .unwrap_or_default();
-
     let for_ = impl_.self_ty.clean(cx);
     let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
         DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
@@ -1946,7 +1941,6 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
             span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx),
             unsafety: impl_.unsafety,
             generics: impl_.generics.clean(cx),
-            provided_trait_methods: provided.clone(),
             trait_,
             for_,
             items,
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5e47144588b..33cb11e539b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -4,6 +4,7 @@ use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::lazy::SyncOnceCell as OnceCell;
+use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::{slice, vec};
@@ -90,6 +91,58 @@ impl ExternalCrate {
         tcx.crate_name(self.crate_num)
     }
 
+    crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
+        match self.src(tcx) {
+            FileName::Real(ref p) => match p.local_path().parent() {
+                Some(p) => p.to_path_buf(),
+                None => PathBuf::new(),
+            },
+            _ => PathBuf::new(),
+        }
+    }
+
+    /// Attempts to find where an external crate is located, given that we're
+    /// rendering in to the specified source destination.
+    crate fn location(
+        &self,
+        extern_url: Option<&str>,
+        dst: &std::path::Path,
+        tcx: TyCtxt<'_>,
+    ) -> ExternalLocation {
+        use ExternalLocation::*;
+
+        fn to_remote(url: impl ToString) -> ExternalLocation {
+            let mut url = url.to_string();
+            if !url.ends_with('/') {
+                url.push('/');
+            }
+            Remote(url)
+        }
+
+        // See if there's documentation generated into the local directory
+        // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
+        // Make sure to call `location()` by that time.
+        let local_location = dst.join(&*self.name(tcx).as_str());
+        if local_location.is_dir() {
+            return Local;
+        }
+
+        if let Some(url) = extern_url {
+            return to_remote(url);
+        }
+
+        // Failing that, see if there's an attribute specifying where to find this
+        // external crate
+        let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+        tcx.get_attrs(did)
+            .lists(sym::doc)
+            .filter(|a| a.has_name(sym::html_root_url))
+            .filter_map(|a| a.value_str())
+            .map(to_remote)
+            .next()
+            .unwrap_or(Unknown) // Well, at least we tried.
+    }
+
     crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
         let root = self.def_id();
 
@@ -381,7 +434,7 @@ impl Item {
                         let relative_to = &cx.current;
                         if let Some(ref fragment) = *fragment {
                             let url = match cx.cache().extern_locations.get(&self.def_id.krate) {
-                                Some(&(_, _, ExternalLocation::Local)) => {
+                                Some(ExternalLocation::Local) => {
                                     if relative_to[0] == "std" {
                                         let depth = relative_to.len() - 1;
                                         "../".repeat(depth)
@@ -390,10 +443,10 @@ impl Item {
                                         format!("{}std/", "../".repeat(depth))
                                     }
                                 }
-                                Some(&(_, _, ExternalLocation::Remote(ref s))) => {
+                                Some(ExternalLocation::Remote(ref s)) => {
                                     format!("{}/std/", s.trim_end_matches('/'))
                                 }
-                                Some(&(_, _, ExternalLocation::Unknown)) | None => format!(
+                                Some(ExternalLocation::Unknown) | None => format!(
                                     "https://doc.rust-lang.org/{}/std/",
                                     crate::doc_rust_lang_org_channel(),
                                 ),
@@ -2150,7 +2203,6 @@ crate struct Impl {
     crate span: Span,
     crate unsafety: hir::Unsafety,
     crate generics: Generics,
-    crate provided_trait_methods: FxHashSet<Symbol>,
     crate trait_: Option<Type>,
     crate for_: Type,
     crate items: Vec<Item>,
@@ -2159,6 +2211,15 @@ crate struct Impl {
     crate blanket_impl: Option<Type>,
 }
 
+impl Impl {
+    crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
+        self.trait_
+            .def_id()
+            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
+            .unwrap_or_default()
+    }
+}
+
 #[derive(Clone, Debug)]
 crate struct Import {
     crate kind: ImportKind,
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 8f10ab2d3ac..48eb14ed291 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -120,6 +120,8 @@ crate struct Options {
     /// For example, using ignore-foo to ignore running the doctest on any target that
     /// contains "foo" as a substring
     crate enable_per_target_ignores: bool,
+    /// Do not run doctests, compile them if should_test is active.
+    crate no_run: bool,
 
     /// The path to a rustc-like binary to build tests with. If not set, we
     /// default to loading from `$sysroot/bin/rustc`.
@@ -197,6 +199,7 @@ impl fmt::Debug for Options {
             .field("runtool_args", &self.runtool_args)
             .field("enable-per-target-ignores", &self.enable_per_target_ignores)
             .field("run_check", &self.run_check)
+            .field("no_run", &self.no_run)
             .finish()
     }
 }
@@ -466,6 +469,12 @@ impl Options {
             test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect();
 
         let should_test = matches.opt_present("test");
+        let no_run = matches.opt_present("no-run");
+
+        if !should_test && no_run {
+            diag.err("the `--test` flag must be passed to enable `--no-run`");
+            return Err(1);
+        }
 
         let output =
             matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc"));
@@ -666,6 +675,7 @@ impl Options {
             enable_per_target_ignores,
             test_builder,
             run_check,
+            no_run,
             render_options: RenderOptions {
                 output,
                 external_html,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 466d1b65406..c0157121e19 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -940,13 +940,14 @@ impl Tester for Collector {
                 let report_unused_externs = |uext| {
                     unused_externs.lock().unwrap().push(uext);
                 };
+                let no_run = config.no_run || options.no_run;
                 let res = run_test(
                     &test,
                     &cratename,
                     line,
                     options,
                     config.should_panic,
-                    config.no_run,
+                    no_run,
                     config.test_harness,
                     runtool,
                     runtool_args,
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 8f8bca64e14..8723e47586e 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,21 +1,19 @@
 use std::collections::BTreeMap;
 use std::mem;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::source_map::FileName;
 use rustc_span::symbol::sym;
-use rustc_span::Symbol;
 
 use crate::clean::{self, GetDefId};
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
 use crate::html::markdown::short_markdown_summary;
-use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation};
+use crate::html::render::cache::{get_index_search_type, ExternalLocation};
 use crate::html::render::IndexItem;
 
 /// This cache is used to store information about the [`clean::Crate`] being
@@ -72,7 +70,7 @@ crate struct Cache {
     crate implementors: FxHashMap<DefId, Vec<Impl>>,
 
     /// Cache of where external crate documentation can be found.
-    crate extern_locations: FxHashMap<CrateNum, (Symbol, PathBuf, ExternalLocation)>,
+    crate extern_locations: FxHashMap<CrateNum, ExternalLocation>,
 
     /// Cache of where documentation for primitives can be found.
     crate primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
@@ -155,21 +153,10 @@ impl Cache {
         // Cache where all our extern crates are located
         // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
         for &(n, ref e) in &krate.externs {
-            let src_root = match e.src(tcx) {
-                FileName::Real(ref p) => match p.local_path().parent() {
-                    Some(p) => p.to_path_buf(),
-                    None => PathBuf::new(),
-                },
-                _ => PathBuf::new(),
-            };
             let name = e.name(tcx);
             let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u);
             let did = DefId { krate: n, index: CRATE_DEF_INDEX };
-            self.extern_locations.insert(
-                n,
-                (name, src_root, extern_location(e, extern_url, tcx.get_attrs(did), &dst, tcx)),
-            );
-
+            self.extern_locations.insert(n, e.location(extern_url, &dst, tcx));
             self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module));
         }
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e39652c6dd5..f211a5acf5e 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -16,7 +16,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_target::spec::abi::Abi;
 
-use crate::clean::{self, utils::find_nearest_parent_module, PrimitiveType};
+use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, PrimitiveType};
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::render::cache::ExternalLocation;
@@ -82,6 +82,10 @@ impl Buffer {
         self.buffer.push_str(s);
     }
 
+    crate fn push_buffer(&mut self, other: Buffer) {
+        self.buffer.push_str(&other.buffer);
+    }
+
     // Intended for consumption by write! and writeln! (std::fmt) but without
     // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
     // import).
@@ -461,14 +465,14 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Option<(String, ItemType, Vec<Str
                 fqp,
                 shortty,
                 match cache.extern_locations[&did.krate] {
-                    (.., ExternalLocation::Remote(ref s)) => {
+                    ExternalLocation::Remote(ref s) => {
                         let s = s.trim_end_matches('/');
                         let mut s = vec![&s[..]];
                         s.extend(module_fqp[..].iter().map(String::as_str));
                         s
                     }
-                    (.., ExternalLocation::Local) => href_relative_parts(module_fqp, relative_to),
-                    (.., ExternalLocation::Unknown) => return None,
+                    ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
+                    ExternalLocation::Unknown => return None,
                 },
             )
         }
@@ -574,12 +578,14 @@ fn primitive_link(
             Some(&def_id) => {
                 let cname_str;
                 let loc = match m.extern_locations[&def_id.krate] {
-                    (ref cname, _, ExternalLocation::Remote(ref s)) => {
-                        cname_str = cname.as_str();
+                    ExternalLocation::Remote(ref s) => {
+                        cname_str =
+                            ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
                         Some(vec![s.trim_end_matches('/'), &cname_str[..]])
                     }
-                    (ref cname, _, ExternalLocation::Local) => {
-                        cname_str = cname.as_str();
+                    ExternalLocation::Local => {
+                        cname_str =
+                            ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
                         Some(if cx.current.first().map(|x| &x[..]) == Some(&cname_str[..]) {
                             iter::repeat("..").take(cx.current.len() - 1).collect()
                         } else {
@@ -587,7 +593,7 @@ fn primitive_link(
                             iter::repeat("..").take(cx.current.len()).chain(cname).collect()
                         })
                     }
-                    (.., ExternalLocation::Unknown) => None,
+                    ExternalLocation::Unknown => None,
                 };
                 if let Some(loc) = loc {
                     write!(
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index f4296a04e59..27a8065afb6 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -1,15 +1,13 @@
 use std::collections::BTreeMap;
-use std::path::Path;
 
-use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
 use crate::clean::types::{
-    AttributesExt, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
+    FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
 };
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
@@ -26,47 +24,6 @@ crate enum ExternalLocation {
     Unknown,
 }
 
-/// Attempts to find where an external crate is located, given that we're
-/// rendering in to the specified source destination.
-crate fn extern_location(
-    e: &clean::ExternalCrate,
-    extern_url: Option<&str>,
-    ast_attrs: &[ast::Attribute],
-    dst: &Path,
-    tcx: TyCtxt<'_>,
-) -> ExternalLocation {
-    use ExternalLocation::*;
-    // See if there's documentation generated into the local directory
-    let local_location = dst.join(&*e.name(tcx).as_str());
-    if local_location.is_dir() {
-        return Local;
-    }
-
-    if let Some(url) = extern_url {
-        let mut url = url.to_string();
-        if !url.ends_with('/') {
-            url.push('/');
-        }
-        return Remote(url);
-    }
-
-    // Failing that, see if there's an attribute specifying where to find this
-    // external crate
-    ast_attrs
-        .lists(sym::doc)
-        .filter(|a| a.has_name(sym::html_root_url))
-        .filter_map(|a| a.value_str())
-        .map(|url| {
-            let mut url = url.to_string();
-            if !url.ends_with('/') {
-                url.push('/')
-            }
-            Remote(url)
-        })
-        .next()
-        .unwrap_or(Unknown) // Well, at least we tried.
-}
-
 /// Builds the search index from the collected metadata
 crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String {
     let mut defid_to_pathid = FxHashMap::default();
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 4c8ba0e7b49..293c0a40fa7 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -18,7 +18,7 @@ use super::print_item::{full_path, item_path, print_item};
 use super::write_shared::write_shared;
 use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS};
 
-use crate::clean;
+use crate::clean::{self, ExternalCrate};
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
@@ -304,12 +304,16 @@ impl<'tcx> Context<'tcx> {
             }
         } else {
             let (krate, src_root) = match *self.cache.extern_locations.get(&cnum)? {
-                (name, ref src, ExternalLocation::Local) => (name, src),
-                (name, ref src, ExternalLocation::Remote(ref s)) => {
+                ExternalLocation::Local => {
+                    let e = ExternalCrate { crate_num: cnum };
+                    (e.name(self.tcx()), e.src_root(self.tcx()))
+                }
+                ExternalLocation::Remote(ref s) => {
                     root = s.to_string();
-                    (name, src)
+                    let e = ExternalCrate { crate_num: cnum };
+                    (e.name(self.tcx()), e.src_root(self.tcx()))
                 }
-                (_, _, ExternalLocation::Unknown) => return None,
+                ExternalLocation::Unknown => return None,
             };
 
             sources::clean_path(&src_root, file, false, |component| {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 19b8dd15ad0..0a8026ef942 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -726,7 +726,8 @@ fn render_impls(
         .iter()
         .map(|i| {
             let did = i.trait_did_full(cache).unwrap();
-            let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
+            let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
+            let assoc_link = AssocItemLink::GotoSource(did, &provided_trait_methods);
             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
             render_impl(
                 &mut buffer,
@@ -1281,99 +1282,6 @@ fn render_impl(
     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
     let mut close_tags = String::new();
 
-    if render_mode == RenderMode::Normal {
-        let id = cx.derive_id(match i.inner_impl().trait_ {
-            Some(ref t) => {
-                if is_on_foreign_type {
-                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
-                } else {
-                    format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
-                }
-            }
-            None => "impl".to_string(),
-        });
-        let aliases = if aliases.is_empty() {
-            String::new()
-        } else {
-            format!(" aliases=\"{}\"", aliases.join(","))
-        };
-        if let Some(use_absolute) = use_absolute {
-            write!(
-                w,
-                "<details class=\"rustdoc-toggle implementors-toggle\" open>\
-                     <summary>\
-                         <h3 id=\"{}\" class=\"impl\"{}>\
-                             <code class=\"in-band\">",
-                id, aliases
-            );
-            close_tags.insert_str(0, "</details>");
-            write!(w, "{}", i.inner_impl().print(use_absolute, cx));
-            if show_def_docs {
-                for it in &i.inner_impl().items {
-                    if let clean::TypedefItem(ref tydef, _) = *it.kind {
-                        w.write_str("<span class=\"where fmt-newline\">  ");
-                        assoc_type(
-                            w,
-                            it,
-                            &[],
-                            Some(&tydef.type_),
-                            AssocItemLink::Anchor(None),
-                            "",
-                            cx,
-                        );
-                        w.write_str(";</span>");
-                    }
-                }
-            }
-            w.write_str("</code>");
-        } else {
-            write!(
-                w,
-                "<details class=\"rustdoc-toggle implementors-toggle\" open>\
-                     <summary>\
-                         <h3 id=\"{}\" class=\"impl\"{}>\
-                             <code class=\"in-band\">{}</code>",
-                id,
-                aliases,
-                i.inner_impl().print(false, cx)
-            );
-            close_tags.insert_str(0, "</details>");
-        }
-        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-        render_stability_since_raw(
-            w,
-            i.impl_item.stable_since(tcx).as_deref(),
-            i.impl_item.const_stable_since(tcx).as_deref(),
-            outer_version,
-            outer_const_version,
-        );
-        write_srclink(cx, &i.impl_item, w);
-        w.write_str("</h3></summary>");
-
-        if trait_.is_some() {
-            if let Some(portability) = portability(&i.impl_item, Some(parent)) {
-                write!(w, "<div class=\"item-info\">{}</div>", portability);
-            }
-        }
-
-        if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
-            let mut ids = cx.id_map.borrow_mut();
-            write!(
-                w,
-                "<div class=\"docblock\">{}</div>",
-                Markdown(
-                    &*dox,
-                    &i.impl_item.links(cx),
-                    &mut ids,
-                    cx.shared.codes,
-                    cx.shared.edition(),
-                    &cx.shared.playground
-                )
-                .into_string()
-            );
-        }
-    }
-
     fn doc_impl_item(
         w: &mut Buffer,
         cx: &Context<'_>,
@@ -1549,11 +1457,10 @@ fn render_impl(
         }
     }
 
-    w.write_str("<div class=\"impl-items\">");
-    close_tags.insert_str(0, "</div>");
+    let mut impl_items = Buffer::empty_from(w);
     for trait_item in &i.inner_impl().items {
         doc_impl_item(
-            w,
+            &mut impl_items,
             cx,
             trait_item,
             if trait_.is_some() { &i.impl_item } else { parent },
@@ -1584,7 +1491,8 @@ fn render_impl(
                 continue;
             }
             let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
-            let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
+            let provided_methods = i.provided_trait_methods(cx.tcx());
+            let assoc_link = AssocItemLink::GotoSource(did, &provided_methods);
 
             doc_impl_item(
                 w,
@@ -1609,7 +1517,7 @@ fn render_impl(
     if show_default_items {
         if let Some(t) = trait_ {
             render_default_items(
-                w,
+                &mut impl_items,
                 cx,
                 &t.trait_,
                 &i.inner_impl(),
@@ -1621,6 +1529,111 @@ fn render_impl(
             );
         }
     }
+    let details_str = if impl_items.is_empty() {
+        ""
+    } else {
+        "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+    };
+    if render_mode == RenderMode::Normal {
+        let id = cx.derive_id(match i.inner_impl().trait_ {
+            Some(ref t) => {
+                if is_on_foreign_type {
+                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
+                } else {
+                    format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
+                }
+            }
+            None => "impl".to_string(),
+        });
+        let aliases = if aliases.is_empty() {
+            String::new()
+        } else {
+            format!(" data-aliases=\"{}\"", aliases.join(","))
+        };
+        if let Some(use_absolute) = use_absolute {
+            write!(
+                w,
+                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
+                details_str, id, aliases
+            );
+            if !impl_items.is_empty() {
+                close_tags.insert_str(0, "</details>");
+            }
+            write!(w, "{}", i.inner_impl().print(use_absolute, cx));
+            if show_def_docs {
+                for it in &i.inner_impl().items {
+                    if let clean::TypedefItem(ref tydef, _) = *it.kind {
+                        w.write_str("<span class=\"where fmt-newline\">  ");
+                        assoc_type(
+                            w,
+                            it,
+                            &[],
+                            Some(&tydef.type_),
+                            AssocItemLink::Anchor(None),
+                            "",
+                            cx,
+                        );
+                        w.write_str(";</span>");
+                    }
+                }
+            }
+            w.write_str("</code>");
+        } else {
+            write!(
+                w,
+                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
+                details_str,
+                id,
+                aliases,
+                i.inner_impl().print(false, cx)
+            );
+            if !impl_items.is_empty() {
+                close_tags.insert_str(0, "</details>");
+            }
+        }
+        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+        render_stability_since_raw(
+            w,
+            i.impl_item.stable_since(tcx).as_deref(),
+            i.impl_item.const_stable_since(tcx).as_deref(),
+            outer_version,
+            outer_const_version,
+        );
+        write_srclink(cx, &i.impl_item, w);
+        if impl_items.is_empty() {
+            w.write_str("</h3>");
+        } else {
+            w.write_str("</h3></summary>");
+        }
+
+        if trait_.is_some() {
+            if let Some(portability) = portability(&i.impl_item, Some(parent)) {
+                write!(w, "<div class=\"item-info\">{}</div>", portability);
+            }
+        }
+
+        if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
+            let mut ids = cx.id_map.borrow_mut();
+            write!(
+                w,
+                "<div class=\"docblock\">{}</div>",
+                Markdown(
+                    &*dox,
+                    &i.impl_item.links(cx),
+                    &mut ids,
+                    cx.shared.codes,
+                    cx.shared.edition(),
+                    &cx.shared.playground
+                )
+                .into_string()
+            );
+        }
+    }
+    if !impl_items.is_empty() {
+        w.write_str("<div class=\"impl-items\">");
+        w.push_buffer(impl_items);
+        close_tags.insert_str(0, "</div>");
+    }
     w.write_str(&close_tags);
 }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 1bb1db00e88..1bf726dd31a 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -669,10 +669,9 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
 
             for implementor in foreign {
-                let assoc_link = AssocItemLink::GotoSource(
-                    implementor.impl_item.def_id,
-                    &implementor.inner_impl().provided_trait_methods,
-                );
+                let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx());
+                let assoc_link =
+                    AssocItemLink::GotoSource(implementor.impl_item.def_id, &provided_methods);
                 render_impl(
                     w,
                     cx,
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 7fbb97beae7..e81eaca8f0e 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -834,7 +834,7 @@ function hideThemeButtonState() {
             // (like "Send" and "Sync").
             var inlined_types = new Set();
             onEachLazy(synthetic_implementors.getElementsByClassName("impl"), function(el) {
-                var aliases = el.getAttribute("aliases");
+                var aliases = el.getAttribute("data-aliases");
                 if (!aliases) {
                     return;
                 }
@@ -1490,27 +1490,42 @@ function hideThemeButtonState() {
     searchState.setup();
 }());
 
-function copy_path(but) {
-    var parent = but.parentElement;
-    var path = [];
+(function () {
+    var reset_button_timeout = null;
 
-    onEach(parent.childNodes, function(child) {
-        if (child.tagName === 'A') {
-            path.push(child.textContent);
-        }
-    });
+    window.copy_path = function(but) {
+        var parent = but.parentElement;
+        var path = [];
 
-    var el = document.createElement('textarea');
-    el.value = 'use ' + path.join('::') + ';';
-    el.setAttribute('readonly', '');
-    // To not make it appear on the screen.
-    el.style.position = 'absolute';
-    el.style.left = '-9999px';
+        onEach(parent.childNodes, function(child) {
+            if (child.tagName === 'A') {
+                path.push(child.textContent);
+            }
+        });
 
-    document.body.appendChild(el);
-    el.select();
-    document.execCommand('copy');
-    document.body.removeChild(el);
+        var el = document.createElement('textarea');
+        el.value = 'use ' + path.join('::') + ';';
+        el.setAttribute('readonly', '');
+        // To not make it appear on the screen.
+        el.style.position = 'absolute';
+        el.style.left = '-9999px';
 
-    but.textContent = '✓';
-}
+        document.body.appendChild(el);
+        el.select();
+        document.execCommand('copy');
+        document.body.removeChild(el);
+
+        but.textContent = '✓';
+
+        if (reset_button_timeout !== null) {
+            window.clearTimeout(reset_button_timeout);
+        }
+
+        function reset_button() {
+            but.textContent = '⎘';
+            reset_button_timeout = null;
+        }
+
+        reset_button_timeout = window.setTimeout(reset_button, 1000);
+    };
+}());
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index a024fa49b0e..a95c90e999f 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -117,9 +117,12 @@ h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
 }
 h1.fqn {
 	display: flex;
-	width: 100%;
 	border-bottom: 1px dashed;
 	margin-top: 0;
+
+	/* workaround to keep flex from breaking below 700 px width due to the float: right on the nav
+	   above the h1 */
+	padding-left: 1px;
 }
 h1.fqn > .in-band > a:hover {
 	text-decoration: underline;
@@ -385,17 +388,9 @@ nav.sub {
 	position: relative;
 }
 
-#results {
-	position: absolute;
-	right: 0;
-	left: 0;
-	overflow: auto;
-}
-
 #results > table {
 	width: 100%;
 	table-layout: fixed;
-	margin-bottom: 40px;
 }
 
 .content pre.line-numbers {
@@ -453,20 +448,14 @@ nav.sub {
 }
 
 .content .out-of-band {
-	float: right;
+	flex-grow: 0;
+	text-align: right;
 	font-size: 23px;
 	margin: 0px;
-	padding: 0px;
+	padding: 0 0 0 12px;
 	font-weight: normal;
 }
 
-h1.fqn > .out-of-band {
-	float: unset;
-	flex: 1;
-	text-align: right;
-	margin-left: 8px;
-}
-
 h3.impl > .out-of-band {
 	font-size: 21px;
 }
@@ -486,6 +475,7 @@ h4 > code, h3 > code, .invisible > code {
 }
 
 .content .in-band {
+	flex-grow: 1;
 	margin: 0px;
 	padding: 0px;
 }
@@ -1484,10 +1474,6 @@ h4 > .notable-traits {
 		display: none !important;
 	}
 
-	h1.fqn {
-		overflow: initial;
-	}
-
 	.theme-picker {
 		left: 10px;
 		top: 54px;
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 2d8c347c3c1..8ca6342462f 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -453,10 +453,10 @@ impl FromWithTcx<clean::Trait> for Trait {
 
 impl FromWithTcx<clean::Impl> for Impl {
     fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
+        let provided_trait_methods = impl_.provided_trait_methods(tcx);
         let clean::Impl {
             unsafety,
             generics,
-            provided_trait_methods,
             trait_,
             for_,
             items,
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 96ea4b6c3b8..ae4d1be3ec2 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -17,7 +17,7 @@ use rustc_session::Session;
 
 use rustdoc_json_types as types;
 
-use crate::clean;
+use crate::clean::{self, ExternalCrate};
 use crate::config::RenderOptions;
 use crate::error::Error;
 use crate::formats::cache::Cache;
@@ -218,12 +218,13 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .cache
                 .extern_locations
                 .iter()
-                .map(|(k, v)| {
+                .map(|(crate_num, external_location)| {
+                    let e = ExternalCrate { crate_num: *crate_num };
                     (
-                        k.as_u32(),
+                        crate_num.as_u32(),
                         types::ExternalCrate {
-                            name: v.0.to_string(),
-                            html_root_url: match &v.2 {
+                            name: e.name(self.tcx).to_string(),
+                            html_root_url: match external_location {
                                 ExternalLocation::Remote(s) => Some(s.clone()),
                                 _ => None,
                             },
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 26aaf0db6f6..2a25b595625 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -16,7 +16,7 @@
 #![feature(type_ascription)]
 #![feature(iter_intersperse)]
 #![recursion_limit = "256"]
-#![deny(rustc::internal)]
+#![warn(rustc::internal)]
 
 #[macro_use]
 extern crate lazy_static;
@@ -595,6 +595,7 @@ fn opts() -> Vec<RustcOptGroup> {
                 "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
             )
         }),
+        unstable("no-run", |o| o.optflag("", "no-run", "Compile doctests without running them")),
     ]
 }
 
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 0ed6038a318e34e3d76a9e55bdebc4cfd17f902
+Subproject b61c24f3521303d442fa86fe691bc8e6acc1510
diff --git a/src/test/assembly/stack-probes.rs b/src/test/assembly/stack-probes.rs
deleted file mode 100644
index 9597e242f1b..00000000000
--- a/src/test/assembly/stack-probes.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-// min-llvm-version: 11.0.1
-// revisions: x86_64 i686
-// assembly-output: emit-asm
-//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
-//[i686] compile-flags: --target i686-unknown-linux-gnu
-// compile-flags: -C llvm-args=--x86-asm-syntax=intel
-
-#![feature(no_core, lang_items)]
-#![crate_type = "lib"]
-#![no_core]
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-
-impl Copy for u8 {}
-
-// Check that inline-asm stack probes are generated correctly.
-// To avoid making this test fragile to slight asm changes,
-// we only check that the stack pointer is decremented by a page at a time,
-// instead of matching the whole probe sequence.
-
-// CHECK-LABEL: small_stack_probe:
-#[no_mangle]
-pub fn small_stack_probe(x: u8, f: fn([u8; 8192])) {
-    // CHECK-NOT: __rust_probestack
-    // x86_64: sub rsp, 4096
-    // i686: sub esp, 4096
-    let a = [x; 8192];
-    f(a);
-}
-
-// CHECK-LABEL: big_stack_probe:
-#[no_mangle]
-pub fn big_stack_probe(x: u8, f: fn([u8; 65536])) {
-    // CHECK-NOT: __rust_probestack
-    // x86_64: sub rsp, 4096
-    // i686: sub esp, 4096
-    let a = [x; 65536];
-    f(a);
-}
diff --git a/src/test/codegen/asm-multiple-options.rs b/src/test/codegen/asm-multiple-options.rs
index c702742bf1a..baf9f3e9bd1 100644
--- a/src/test/codegen/asm-multiple-options.rs
+++ b/src/test/codegen/asm-multiple-options.rs
@@ -10,7 +10,7 @@
 #[no_mangle]
 pub unsafe fn pure(x: i32) {
     let y: i32;
-    asm!("", out("ax") y, in("bx") x, options(pure), options(nomem));
+    asm!("", out("ax") y, in("cx") x, options(pure), options(nomem));
 }
 
 pub static mut VAR: i32 = 0;
diff --git a/src/test/codegen/asm-options.rs b/src/test/codegen/asm-options.rs
index 21e7eb43796..70391661b0c 100644
--- a/src/test/codegen/asm-options.rs
+++ b/src/test/codegen/asm-options.rs
@@ -10,7 +10,7 @@
 #[no_mangle]
 pub unsafe fn pure(x: i32) {
     let y: i32;
-    asm!("", out("ax") y, in("bx") x, options(pure, nomem));
+    asm!("", out("ax") y, in("cx") x, options(pure, nomem));
 }
 
 // CHECK-LABEL: @noreturn
diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs
index 2b8c0dfc229..f2641404aae 100644
--- a/src/test/codegen/async-fn-debug-msvc.rs
+++ b/src/test/codegen/async-fn-debug-msvc.rs
@@ -1,7 +1,7 @@
 // Verify debuginfo for generators:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2 --edition=2018
@@ -17,26 +17,32 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 12,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
diff --git a/src/test/codegen/async-fn-debug.rs b/src/test/codegen/async-fn-debug.rs
index e9b774b48c3..7de115f7e91 100644
--- a/src/test/codegen/async-fn-debug.rs
+++ b/src/test/codegen/async-fn-debug.rs
@@ -1,7 +1,7 @@
 // Verify debuginfo for async fn:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2 --edition=2018
@@ -17,29 +17,36 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]]
 // CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: discriminator: [[DISC:![0-9]*]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 12,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs
index 4f8a320ee9b..44be71f3b9b 100644
--- a/src/test/codegen/generator-debug-msvc.rs
+++ b/src/test/codegen/generator-debug-msvc.rs
@@ -1,7 +1,7 @@
 // Verify debuginfo for generators:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2
@@ -21,26 +21,32 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 17,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs
index 86ac6db702a..8b87a2f0646 100644
--- a/src/test/codegen/generator-debug.rs
+++ b/src/test/codegen/generator-debug.rs
@@ -1,7 +1,7 @@
 // Verify debuginfo for generators:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2 --edition=2018
@@ -21,29 +21,36 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]]
 // CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: discriminator: [[DISC:![0-9]*]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 17,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs
index b05787df8e3..9bd351df3ea 100644
--- a/src/test/codegen/stack-probes.rs
+++ b/src/test/codegen/stack-probes.rs
@@ -13,12 +13,10 @@
 // ignore-emscripten
 // ignore-windows
 // compile-flags: -C no-prepopulate-passes
-// min-llvm-version: 11.0.1
 
 #![crate_type = "lib"]
 
 #[no_mangle]
 pub fn foo() {
 // CHECK: @foo() unnamed_addr #0
-// CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} }
 }
diff --git a/src/test/debuginfo/extern-c-fn.rs b/src/test/debuginfo/extern-c-fn.rs
index 5043e7d9b8a..17a452ec634 100644
--- a/src/test/debuginfo/extern-c-fn.rs
+++ b/src/test/debuginfo/extern-c-fn.rs
@@ -5,17 +5,16 @@
 // === GDB TESTS ===================================================================================
 // gdb-command:run
 
-// gdb-command:print s
-// gdbg-check:$1 = [...]"abcd"
-// gdbr-check:$1 = [...]"abcd\000"
+// gdb-command:printf "s = \"%s\"\n", s
+// gdb-check:s = "abcd"
 // gdb-command:print len
-// gdb-check:$2 = 20
+// gdb-check:$1 = 20
 // gdb-command:print local0
-// gdb-check:$3 = 19
+// gdb-check:$2 = 19
 // gdb-command:print local1
-// gdb-check:$4 = true
+// gdb-check:$3 = true
 // gdb-command:print local2
-// gdb-check:$5 = 20.5
+// gdb-check:$4 = 20.5
 
 // gdb-command:continue
 
diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs
index b65471011fd..1beed1c835d 100644
--- a/src/test/debuginfo/generator-objects.rs
+++ b/src/test/debuginfo/generator-objects.rs
@@ -1,37 +1,41 @@
 // Require a gdb that can read DW_TAG_variant_part.
 // min-gdb-version: 8.2
 
+// LLDB without native Rust support cannot read DW_TAG_variant_part,
+// so it prints nothing for generators. But those tests are kept to
+// ensure that LLDB won't crash at least (like #57822).
+
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
 
 // gdb-command:run
 // gdb-command:print b
-// gdb-check:$1 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 0, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$1 = generator_objects::main::generator-0::Unresumed(0x[...])
 // gdb-command:continue
 // gdb-command:print b
-// gdb-check:$2 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 3, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$2 = generator_objects::main::generator-0::Suspend0{c: 6, d: 7, __0: 0x[...]}
 // gdb-command:continue
 // gdb-command:print b
-// gdb-check:$3 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 4, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {c: 7, d: 8}}}
+// gdb-check:$3 = generator_objects::main::generator-0::Suspend1{c: 7, d: 8, __0: 0x[...]}
 // gdb-command:continue
 // gdb-command:print b
-// gdb-check:$4 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 1, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$4 = generator_objects::main::generator-0::Returned(0x[...])
 
 // === LLDB TESTS ==================================================================================
 
 // lldb-command:run
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $0 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $0 =
 // lldb-command:continue
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $1 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $1 =
 // lldb-command:continue
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $2 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $2 =
 // lldb-command:continue
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $3 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $3 =
 
 #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
 #![omit_gdb_pretty_printer_section]
diff --git a/src/test/debuginfo/issue-57822.rs b/src/test/debuginfo/issue-57822.rs
index a68e4c0a556..6b2b12edda5 100644
--- a/src/test/debuginfo/issue-57822.rs
+++ b/src/test/debuginfo/issue-57822.rs
@@ -14,7 +14,7 @@
 // gdb-check:$1 = issue_57822::main::closure-1 (issue_57822::main::closure-0 (1))
 
 // gdb-command:print b
-// gdb-check:$2 = issue_57822::main::generator-3 {__0: issue_57822::main::generator-2 {__0: 2, <<variant>>: {[...]}}, <<variant>>: {[...]}}
+// gdb-check:$2 = issue_57822::main::generator-3::Unresumed(issue_57822::main::generator-2::Unresumed(2))
 
 // === LLDB TESTS ==================================================================================
 
@@ -24,7 +24,7 @@
 // lldbg-check:(issue_57822::main::closure-1) $0 = { 0 = { 0 = 1 } }
 
 // lldb-command:print b
-// lldbg-check:(issue_57822::main::generator-3) $1 = { 0 = { 0 = 2 } }
+// lldbg-check:(issue_57822::main::generator-3) $1 =
 
 #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
 #![omit_gdb_pretty_printer_section]
diff --git a/src/test/debuginfo/pretty-huge-vec.rs b/src/test/debuginfo/pretty-huge-vec.rs
index cbd2278f7e2..67155b4e9f0 100644
--- a/src/test/debuginfo/pretty-huge-vec.rs
+++ b/src/test/debuginfo/pretty-huge-vec.rs
@@ -13,7 +13,7 @@
 // gdb-check:$1 = Vec(size=1000000000) = {[...]...}
 
 // gdb-command: print slice
-// gdb-check:$2 = &[u8] {data_ptr: [...]"\000", length: 1000000000}
+// gdb-check:$2 = &[u8] {data_ptr: [...], length: 1000000000}
 
 #![allow(unused_variables)]
 
diff --git a/src/test/incremental/commandline-args.rs b/src/test/incremental/commandline-args.rs
index 08a0232f661..35b7183db7f 100644
--- a/src/test/incremental/commandline-args.rs
+++ b/src/test/incremental/commandline-args.rs
@@ -2,20 +2,23 @@
 // the cache while changing an untracked one doesn't.
 
 // ignore-asmjs wasm2js does not support source maps yet
-// revisions:rpass1 rpass2 rpass3
+// revisions:rpass1 rpass2 rpass3 rpass4
 // compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
 #![rustc_partition_codegened(module="commandline_args", cfg="rpass2")]
 #![rustc_partition_reused(module="commandline_args", cfg="rpass3")]
+#![rustc_partition_codegened(module="commandline_args", cfg="rpass4")]
 
 // Between revisions 1 and 2, we are changing the debuginfo-level, which should
 // invalidate the cache. Between revisions 2 and 3, we are adding `--verbose`
-// which should have no effect on the cache:
+// which should have no effect on the cache. Between revisions, we are adding
+// `--remap-path-prefix` which should invalidate the cache:
 //[rpass1] compile-flags: -C debuginfo=0
 //[rpass2] compile-flags: -C debuginfo=2
 //[rpass3] compile-flags: -C debuginfo=2 --verbose
+//[rpass4] compile-flags: -C debuginfo=2 --verbose --remap-path-prefix=/home/bors/rust=src
 
 pub fn main() {
     // empty
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
index ee7b258cec4..70ce81bd473 100644
--- a/src/test/incremental/hashes/inherent_impls.rs
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -23,7 +23,7 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_clean(cfg="cfail3")]
@@ -85,7 +85,7 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_nodes")]
@@ -100,7 +100,7 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")]
@@ -135,7 +135,7 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_clean(cfg="cfail2")]
@@ -468,7 +468,7 @@ impl Bar<u32> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Bar<u64> {
     #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")]
diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs
index 495445670c0..d874be060c2 100644
--- a/src/test/incremental/hashes/type_defs.rs
+++ b/src/test/incremental/hashes/type_defs.rs
@@ -24,7 +24,7 @@
 type ChangePrimitiveType = i32;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangePrimitiveType = i64;
 
@@ -35,7 +35,7 @@ type ChangePrimitiveType = i64;
 type ChangeMutability = &'static i32;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeMutability = &'static mut i32;
 
@@ -60,7 +60,7 @@ struct Struct2;
 type ChangeTypeStruct = Struct1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeStruct = Struct2;
 
@@ -71,7 +71,7 @@ type ChangeTypeStruct = Struct2;
 type ChangeTypeTuple = (u32, u64);
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeTuple = (u32, i64);
 
@@ -91,7 +91,7 @@ enum Enum2 {
 type ChangeTypeEnum = Enum1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeEnum = Enum2;
 
@@ -102,7 +102,7 @@ type ChangeTypeEnum = Enum2;
 type AddTupleField = (i32, i64);
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type AddTupleField = (i32, i64, i16);
 
@@ -113,7 +113,7 @@ type AddTupleField = (i32, i64, i16);
 type ChangeNestedTupleField = (i32, (i64, i16));
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeNestedTupleField = (i32, (i64, i8));
 
diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs
index 4f5f6169f36..8df54467e5e 100644
--- a/src/test/incremental/ich_nested_items.rs
+++ b/src/test/incremental/ich_nested_items.rs
@@ -14,10 +14,7 @@ pub fn foo() {
     #[cfg(cfail1)]
     pub fn baz() {} // order is different...
 
-    // FIXME: Make "hir_owner" use `rustc_clean` here. Currently "hir_owner" includes a reference to
-    // the parent node, which is the statement holding this item. Changing the position of
-    // `bar` in `foo` will update that reference and make `hir_owner(bar)` dirty.
-    #[rustc_dirty(label = "hir_owner", cfg = "cfail2")]
+    #[rustc_clean(label = "hir_owner", cfg = "cfail2")]
     #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")]
     pub fn bar() {} // but that doesn't matter.
 
diff --git a/src/test/pretty/asm.pp b/src/test/pretty/asm.pp
index c86d8a11971..a2065039692 100644
--- a/src/test/pretty/asm.pp
+++ b/src/test/pretty/asm.pp
@@ -21,7 +21,7 @@ pub fn main() {
         asm!("{0}", out(reg) a);
         asm!("{0}", inout(reg) b);
         asm!("{0} {1}", out(reg) _, inlateout(reg) b => _);
-        asm!("", out("al") _, lateout("rbx") _);
+        asm!("", out("al") _, lateout("rcx") _);
         asm!("inst1\ninst2");
         asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
         asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b);
diff --git a/src/test/pretty/asm.rs b/src/test/pretty/asm.rs
index 33f25e5216b..1156ab769a0 100644
--- a/src/test/pretty/asm.rs
+++ b/src/test/pretty/asm.rs
@@ -15,7 +15,7 @@ pub fn main() {
         asm!("{0}", out(reg) a);
         asm!("{name}", name = inout(reg) b);
         asm!("{} {}", out(reg) _, inlateout(reg) b => _);
-        asm!("", out("al") _, lateout("rbx") _);
+        asm!("", out("al") _, lateout("rcx") _);
         asm!("inst1", "inst2");
         asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
         asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt
new file mode 100644
index 00000000000..a030035f13b
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt
@@ -0,0 +1,42 @@
+    1|       |// compile-flags: --edition=2018
+    2|       |#![feature(no_coverage)]
+    3|       |
+    4|       |macro_rules! bail {
+    5|       |    ($msg:literal $(,)?) => {
+    6|       |        if $msg.len() > 0 {
+    7|       |            println!("no msg");
+    8|       |        } else {
+    9|       |            println!($msg);
+   10|       |        }
+   11|       |        return Err(String::from($msg));
+   12|       |    };
+   13|       |}
+   14|       |
+   15|       |macro_rules! on_error {
+   16|       |    ($value:expr, $error_message:expr) => {
+   17|      0|        $value.or_else(|e| {
+   18|      0|            let message = format!($error_message, e);
+   19|      0|            if message.len() > 0 {
+   20|      0|                println!("{}", message);
+   21|      0|                Ok(String::from("ok"))
+   22|       |            } else {
+   23|      0|                bail!("error");
+   24|       |            }
+   25|      0|        })
+   26|       |    };
+   27|       |}
+   28|       |
+   29|      1|fn load_configuration_files() -> Result<String, String> {
+   30|      1|    Ok(String::from("config"))
+   31|      1|}
+   32|       |
+   33|      1|pub fn main() -> Result<(), String> {
+   34|      1|    println!("Starting service");
+   35|      1|    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+                                                                                                 ^0
+   36|       |
+   37|      1|    let startup_delay_duration = String::from("arg");
+   38|      1|    let _ = (config, startup_delay_duration);
+   39|      1|    Ok(())
+   40|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt
new file mode 100644
index 00000000000..a954eb30378
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt
@@ -0,0 +1,83 @@
+    1|       |// compile-flags: --edition=2018
+    2|       |#![feature(no_coverage)]
+    3|       |
+    4|       |macro_rules! bail {
+    5|       |    ($msg:literal $(,)?) => {
+    6|       |        if $msg.len() > 0 {
+    7|       |            println!("no msg");
+    8|       |        } else {
+    9|       |            println!($msg);
+   10|       |        }
+   11|       |        return Err(String::from($msg));
+   12|       |    };
+   13|       |}
+   14|       |
+   15|       |macro_rules! on_error {
+   16|       |    ($value:expr, $error_message:expr) => {
+   17|      0|        $value.or_else(|e| {
+   18|      0|            let message = format!($error_message, e);
+   19|      0|            if message.len() > 0 {
+   20|      0|                println!("{}", message);
+   21|      0|                Ok(String::from("ok"))
+   22|       |            } else {
+   23|      0|                bail!("error");
+   24|       |            }
+   25|      0|        })
+   26|       |    };
+   27|       |}
+   28|       |
+   29|      1|fn load_configuration_files() -> Result<String, String> {
+   30|      1|    Ok(String::from("config"))
+   31|      1|}
+   32|       |
+   33|      1|pub async fn test() -> Result<(), String> {
+   34|      1|    println!("Starting service");
+   35|      1|    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+                                                                                                 ^0
+   36|       |
+   37|      1|    let startup_delay_duration = String::from("arg");
+   38|      1|    let _ = (config, startup_delay_duration);
+   39|      1|    Ok(())
+   40|      1|}
+   41|       |
+   42|       |#[no_coverage]
+   43|       |fn main() {
+   44|       |    executor::block_on(test());
+   45|       |}
+   46|       |
+   47|       |mod executor {
+   48|       |    use core::{
+   49|       |        future::Future,
+   50|       |        pin::Pin,
+   51|       |        task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+   52|       |    };
+   53|       |
+   54|       |    #[no_coverage]
+   55|       |    pub fn block_on<F: Future>(mut future: F) -> F::Output {
+   56|       |        let mut future = unsafe { Pin::new_unchecked(&mut future) };
+   57|       |        use std::hint::unreachable_unchecked;
+   58|       |        static VTABLE: RawWakerVTable = RawWakerVTable::new(
+   59|       |
+   60|       |            #[no_coverage]
+   61|       |            |_| unsafe { unreachable_unchecked() }, // clone
+   62|       |
+   63|       |            #[no_coverage]
+   64|       |            |_| unsafe { unreachable_unchecked() }, // wake
+   65|       |
+   66|       |            #[no_coverage]
+   67|       |            |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+   68|       |
+   69|       |            #[no_coverage]
+   70|       |            |_| (),
+   71|       |        );
+   72|       |        let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+   73|       |        let mut context = Context::from_waker(&waker);
+   74|       |
+   75|       |        loop {
+   76|       |            if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+   77|       |                break val;
+   78|       |            }
+   79|       |        }
+   80|       |    }
+   81|       |}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt
index f5b5184044f..883254a09ba 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt
@@ -1,9 +1,9 @@
     1|       |#![allow(unused_assignments, unused_variables, dead_code)]
     2|       |
     3|      1|fn main() {
-    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-    6|       |    // dependent conditions.
+    4|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|      1|    // dependent conditions.
     7|      1|    let is_true = std::env::args().len() == 1;
     8|      1|
     9|      1|    let mut countdown = 0;
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt
new file mode 100644
index 00000000000..de32c88b725
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt
@@ -0,0 +1,22 @@
+    1|       |// Shows that rust-lang/rust/83601 is resolved
+    2|       |
+    3|      3|#[derive(Debug, PartialEq, Eq)]
+                              ^2
+  ------------------
+  | <issue_83601::Foo as core::cmp::PartialEq>::eq:
+  |    3|      2|#[derive(Debug, PartialEq, Eq)]
+  ------------------
+  | Unexecuted instantiation: <issue_83601::Foo as core::cmp::PartialEq>::ne
+  ------------------
+    4|       |struct Foo(u32);
+    5|       |
+    6|      1|fn main() {
+    7|      1|    let bar = Foo(1);
+    8|      1|    assert_eq!(bar, Foo(1));
+    9|      1|    let baz = Foo(0);
+   10|      1|    assert_ne!(baz, Foo(1));
+   11|      1|    println!("{:?}", Foo(1));
+   12|      1|    println!("{:?}", bar);
+   13|      1|    println!("{:?}", baz);
+   14|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt
new file mode 100644
index 00000000000..f24f7c69404
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt
@@ -0,0 +1,195 @@
+    1|       |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+    2|       |
+    3|       |// expect-exit-status-101
+    4|     21|#[derive(PartialEq, Eq)]
+  ------------------
+  | <issue_84561::Foo as core::cmp::PartialEq>::eq:
+  |    4|     21|#[derive(PartialEq, Eq)]
+  ------------------
+  | Unexecuted instantiation: <issue_84561::Foo as core::cmp::PartialEq>::ne
+  ------------------
+    5|       |struct Foo(u32);
+    6|      1|fn test3() {
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|    let bar = Foo(1);
+    9|      1|    assert_eq!(bar, Foo(1));
+   10|      1|    let baz = Foo(0);
+   11|      1|    assert_ne!(baz, Foo(1));
+   12|      1|    println!("{:?}", Foo(1));
+   13|      1|    println!("{:?}", bar);
+   14|      1|    println!("{:?}", baz);
+   15|      1|
+   16|      1|    assert_eq!(Foo(1), Foo(1));
+   17|      1|    assert_ne!(Foo(0), Foo(1));
+   18|      1|    assert_eq!(Foo(2), Foo(2));
+   19|      1|    let bar = Foo(0);
+   20|      1|    assert_ne!(bar, Foo(3));
+   21|      1|    assert_ne!(Foo(0), Foo(4));
+   22|      1|    assert_eq!(Foo(3), Foo(3), "with a message");
+                                             ^0
+   23|      1|    println!("{:?}", bar);
+   24|      1|    println!("{:?}", Foo(1));
+   25|      1|
+   26|      1|    assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+                                             ^0                 ^0                      ^0
+   27|      1|    assert_ne!(
+   28|       |        Foo(0)
+   29|       |        ,
+   30|       |        Foo(5)
+   31|       |        ,
+   32|      0|        "{}"
+   33|      0|        ,
+   34|      0|        if
+   35|      0|        is_true
+   36|       |        {
+   37|      0|            "true message"
+   38|       |        } else {
+   39|      0|            "false message"
+   40|       |        }
+   41|       |    );
+   42|       |
+   43|      1|    let is_true = std::env::args().len() == 1;
+   44|      1|
+   45|      1|    assert_eq!(
+   46|      1|        Foo(1),
+   47|      1|        Foo(1)
+   48|      1|    );
+   49|      1|    assert_ne!(
+   50|      1|        Foo(0),
+   51|      1|        Foo(1)
+   52|      1|    );
+   53|      1|    assert_eq!(
+   54|      1|        Foo(2),
+   55|      1|        Foo(2)
+   56|      1|    );
+   57|      1|    let bar = Foo(1);
+   58|      1|    assert_ne!(
+   59|      1|        bar,
+   60|      1|        Foo(3)
+   61|      1|    );
+   62|      1|    if is_true {
+   63|      1|        assert_ne!(
+   64|      1|            Foo(0),
+   65|      1|            Foo(4)
+   66|      1|        );
+   67|       |    } else {
+   68|      0|        assert_eq!(
+   69|      0|            Foo(3),
+   70|      0|            Foo(3)
+   71|      0|        );
+   72|       |    }
+   73|      1|    if is_true {
+   74|      1|        assert_ne!(
+   75|       |            Foo(0),
+   76|       |            Foo(4),
+   77|      0|            "with a message"
+   78|       |        );
+   79|       |    } else {
+   80|      0|        assert_eq!(
+   81|       |            Foo(3),
+   82|       |            Foo(3),
+   83|      0|            "with a message"
+   84|       |        );
+   85|       |    }
+   86|      1|    assert_ne!(
+   87|      1|        if is_true {
+   88|      1|            Foo(0)
+   89|       |        } else {
+   90|      0|            Foo(1)
+   91|       |        },
+   92|       |        Foo(5)
+   93|       |    );
+   94|      1|    assert_ne!(
+   95|      1|        Foo(5),
+   96|      1|        if is_true {
+   97|      1|            Foo(0)
+   98|       |        } else {
+   99|      0|            Foo(1)
+  100|       |        }
+  101|       |    );
+  102|      1|    assert_ne!(
+  103|      1|        if is_true {
+  104|      1|            assert_eq!(
+  105|      1|                Foo(3),
+  106|      1|                Foo(3)
+  107|      1|            );
+  108|      1|            Foo(0)
+  109|       |        } else {
+  110|      0|            assert_ne!(
+  111|      0|                if is_true {
+  112|      0|                    Foo(0)
+  113|       |                } else {
+  114|      0|                    Foo(1)
+  115|       |                },
+  116|       |                Foo(5)
+  117|       |            );
+  118|      0|            Foo(1)
+  119|       |        },
+  120|       |        Foo(5),
+  121|      0|        "with a message"
+  122|       |    );
+  123|      1|    assert_eq!(
+  124|       |        Foo(1),
+  125|       |        Foo(3),
+  126|      1|        "this assert should fail"
+  127|       |    );
+  128|      0|    assert_eq!(
+  129|       |        Foo(3),
+  130|       |        Foo(3),
+  131|      0|        "this assert should not be reached"
+  132|       |    );
+  133|      0|}
+  134|       |
+  135|       |impl std::fmt::Debug for Foo {
+  136|       |    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+  137|      7|        write!(f, "try and succeed")?;
+                                                  ^0
+  138|      7|        Ok(())
+  139|      7|    }
+  140|       |}
+  141|       |
+  142|       |static mut DEBUG_LEVEL_ENABLED: bool = false;
+  143|       |
+  144|       |macro_rules! debug {
+  145|       |    ($($arg:tt)+) => (
+  146|       |        if unsafe { DEBUG_LEVEL_ENABLED } {
+  147|       |            println!($($arg)+);
+  148|       |        }
+  149|       |    );
+  150|       |}
+  151|       |
+  152|      1|fn test1() {
+  153|      1|    debug!("debug is enabled");
+                         ^0
+  154|      1|    debug!("debug is enabled");
+                         ^0
+  155|      1|    let _ = 0;
+  156|      1|    debug!("debug is enabled");
+                         ^0
+  157|      1|    unsafe {
+  158|      1|        DEBUG_LEVEL_ENABLED = true;
+  159|      1|    }
+  160|      1|    debug!("debug is enabled");
+  161|      1|}
+  162|       |
+  163|       |macro_rules! call_debug {
+  164|       |    ($($arg:tt)+) => (
+  165|      1|        fn call_print(s: &str) {
+  166|      1|            print!("{}", s);
+  167|      1|        }
+  168|       |
+  169|       |        call_print("called from call_debug: ");
+  170|       |        debug!($($arg)+);
+  171|       |    );
+  172|       |}
+  173|       |
+  174|      1|fn test2() {
+  175|      1|    call_debug!("debug is enabled");
+  176|      1|}
+  177|       |
+  178|      1|fn main() {
+  179|      1|    test1();
+  180|      1|    test2();
+  181|      1|    test3();
+  182|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt
new file mode 100644
index 00000000000..c4a7b0cc7e9
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt
@@ -0,0 +1,18 @@
+    1|       |// Enables `no_coverage` on the entire crate
+    2|       |#![feature(no_coverage)]
+    3|       |
+    4|       |#[no_coverage]
+    5|       |fn do_not_add_coverage_1() {
+    6|       |    println!("called but not covered");
+    7|       |}
+    8|       |
+    9|       |#[no_coverage]
+   10|       |fn do_not_add_coverage_2() {
+   11|       |    println!("called but not covered");
+   12|       |}
+   13|       |
+   14|      1|fn main() {
+   15|      1|    do_not_add_coverage_1();
+   16|      1|    do_not_add_coverage_2();
+   17|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt
new file mode 100644
index 00000000000..16eaf7c858c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt
@@ -0,0 +1,19 @@
+    1|       |// Enables `no_coverage` on individual functions
+    2|       |
+    3|       |#[feature(no_coverage)]
+    4|       |#[no_coverage]
+    5|       |fn do_not_add_coverage_1() {
+    6|       |    println!("called but not covered");
+    7|       |}
+    8|       |
+    9|       |#[no_coverage]
+   10|       |#[feature(no_coverage)]
+   11|       |fn do_not_add_coverage_2() {
+   12|       |    println!("called but not covered");
+   13|       |}
+   14|       |
+   15|      1|fn main() {
+   16|      1|    do_not_add_coverage_1();
+   17|      1|    do_not_add_coverage_2();
+   18|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt
index 4e4dde46b34..fc266653349 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt
@@ -2,7 +2,7 @@
     2|       |// structure of this test.
     3|       |
     4|      2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-                       ^0            ^0      ^0 ^0  ^1       ^1 ^0^0
+                       ^0            ^0      ^0     ^1       ^1 ^0^0
   ------------------
   | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialEq>::ne
   ------------------
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
index c9ebffde039..9fca52451ed 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
@@ -9,7 +9,7 @@
     9|       |    }
    10|      6|}
    11|       |
-   12|      1|fn main() -> Result<(),()> {
+   12|      1|fn test1() -> Result<(),()> {
    13|      1|    let mut
    14|      1|        countdown = 10
    15|       |    ;
@@ -35,4 +35,91 @@
    34|       |    }
    35|      0|    Ok(())
    36|      1|}
+   37|       |
+   38|       |struct Thing1;
+   39|       |impl Thing1 {
+   40|     18|    fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
+   41|     18|        if return_error {
+   42|      1|            Err(())
+   43|       |        } else {
+   44|     17|            Ok(Thing2{})
+   45|       |        }
+   46|     18|    }
+   47|       |}
+   48|       |
+   49|       |struct Thing2;
+   50|       |impl Thing2 {
+   51|     17|    fn call(&self, return_error: bool) -> Result<u32,()> {
+   52|     17|        if return_error {
+   53|      2|            Err(())
+   54|       |        } else {
+   55|     15|            Ok(57)
+   56|       |        }
+   57|     17|    }
+   58|       |}
+   59|       |
+   60|      1|fn test2() -> Result<(),()> {
+   61|      1|    let thing1 = Thing1{};
+   62|      1|    let mut
+   63|      1|        countdown = 10
+   64|       |    ;
+   65|       |    for
+   66|      6|        _
+   67|       |    in
+   68|      6|        0..10
+   69|       |    {
+   70|      6|        countdown
+   71|      6|            -= 1
+   72|      6|        ;
+   73|      6|        if
+   74|      6|            countdown < 5
+   75|       |        {
+   76|      1|            thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+                                                            ^0
+   77|      1|            thing1
+   78|      1|                .
+   79|      1|                get_thing_2(/*return_error=*/ false)
+   80|      0|                ?
+   81|       |                .
+   82|      1|                call(/*return_error=*/ true)
+   83|      1|                .
+   84|      1|                expect_err(
+   85|      1|                    "call should fail"
+   86|      1|                );
+   87|      1|            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+                              ^0                                                ^0                          ^0
+   88|      0|            assert_eq!(val, 57);
+   89|      0|            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+   90|      0|            assert_eq!(val, 57);
+   91|       |        }
+   92|       |        else
+   93|       |        {
+   94|      5|            let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+                                                                               ^0                             ^0
+   95|      5|            assert_eq!(val, 57);
+   96|      5|            let val = thing1
+   97|      5|                .get_thing_2(/*return_error=*/ false)?
+                                                                   ^0
+   98|      5|                .call(/*return_error=*/ false)?;
+                                                            ^0
+   99|      5|            assert_eq!(val, 57);
+  100|      5|            let val = thing1
+  101|      5|                .get_thing_2(/*return_error=*/ false)
+  102|      0|                ?
+  103|      5|                .call(/*return_error=*/ false)
+  104|      0|                ?
+  105|       |                ;
+  106|      5|            assert_eq!(val, 57);
+  107|       |        }
+  108|       |    }
+  109|      0|    Ok(())
+  110|      1|}
+  111|       |
+  112|      1|fn main() -> Result<(),()> {
+  113|      1|    test1().expect_err("test1 should fail");
+  114|      1|    test2()
+  115|      1|    ?
+  116|       |    ;
+  117|      0|    Ok(())
+  118|      1|}
 
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
index f5beb9ef24a..018d2642344 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
@@ -3,9 +3,9 @@
     3|       |use std::fmt::Debug;
     4|       |
     5|      1|pub fn used_function() {
-    6|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-    7|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-    8|       |    // dependent conditions.
+    6|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    7|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    8|      1|    // dependent conditions.
     9|      1|    let is_true = std::env::args().len() == 1;
    10|      1|    let mut countdown = 0;
    11|      1|    if is_true {
@@ -36,12 +36,12 @@
    22|      2|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
    23|      2|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt
index cc98956e307..dab31cbf4ac 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt
@@ -5,9 +5,9 @@
     5|       |use std::fmt::Debug;
     6|       |
     7|      1|pub fn used_function() {
-    8|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-    9|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-   10|       |    // dependent conditions.
+    8|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    9|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+   10|      1|    // dependent conditions.
    11|      1|    let is_true = std::env::args().len() == 1;
    12|      1|    let mut countdown = 0;
    13|      1|    if is_true {
@@ -19,9 +19,9 @@
    18|       |
    19|       |#[inline(always)]
    20|      1|pub fn used_inline_function() {
-   21|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-   22|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-   23|       |    // dependent conditions.
+   21|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+   22|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+   23|      1|    // dependent conditions.
    24|      1|    let is_true = std::env::args().len() == 1;
    25|      1|    let mut countdown = 0;
    26|      1|    if is_true {
diff --git a/src/test/run-make-fulldeps/coverage/closure_macro.rs b/src/test/run-make-fulldeps/coverage/closure_macro.rs
new file mode 100644
index 00000000000..10e434007b8
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/closure_macro.rs
@@ -0,0 +1,40 @@
+// compile-flags: --edition=2018
+#![feature(no_coverage)]
+
+macro_rules! bail {
+    ($msg:literal $(,)?) => {
+        if $msg.len() > 0 {
+            println!("no msg");
+        } else {
+            println!($msg);
+        }
+        return Err(String::from($msg));
+    };
+}
+
+macro_rules! on_error {
+    ($value:expr, $error_message:expr) => {
+        $value.or_else(|e| {
+            let message = format!($error_message, e);
+            if message.len() > 0 {
+                println!("{}", message);
+                Ok(String::from("ok"))
+            } else {
+                bail!("error");
+            }
+        })
+    };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+    Ok(String::from("config"))
+}
+
+pub fn main() -> Result<(), String> {
+    println!("Starting service");
+    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+    let startup_delay_duration = String::from("arg");
+    let _ = (config, startup_delay_duration);
+    Ok(())
+}
diff --git a/src/test/run-make-fulldeps/coverage/closure_macro_async.rs b/src/test/run-make-fulldeps/coverage/closure_macro_async.rs
new file mode 100644
index 00000000000..bcdfd11f899
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/closure_macro_async.rs
@@ -0,0 +1,81 @@
+// compile-flags: --edition=2018
+#![feature(no_coverage)]
+
+macro_rules! bail {
+    ($msg:literal $(,)?) => {
+        if $msg.len() > 0 {
+            println!("no msg");
+        } else {
+            println!($msg);
+        }
+        return Err(String::from($msg));
+    };
+}
+
+macro_rules! on_error {
+    ($value:expr, $error_message:expr) => {
+        $value.or_else(|e| {
+            let message = format!($error_message, e);
+            if message.len() > 0 {
+                println!("{}", message);
+                Ok(String::from("ok"))
+            } else {
+                bail!("error");
+            }
+        })
+    };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+    Ok(String::from("config"))
+}
+
+pub async fn test() -> Result<(), String> {
+    println!("Starting service");
+    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+    let startup_delay_duration = String::from("arg");
+    let _ = (config, startup_delay_duration);
+    Ok(())
+}
+
+#[no_coverage]
+fn main() {
+    executor::block_on(test());
+}
+
+mod executor {
+    use core::{
+        future::Future,
+        pin::Pin,
+        task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+    };
+
+    #[no_coverage]
+    pub fn block_on<F: Future>(mut future: F) -> F::Output {
+        let mut future = unsafe { Pin::new_unchecked(&mut future) };
+        use std::hint::unreachable_unchecked;
+        static VTABLE: RawWakerVTable = RawWakerVTable::new(
+
+            #[no_coverage]
+            |_| unsafe { unreachable_unchecked() }, // clone
+
+            #[no_coverage]
+            |_| unsafe { unreachable_unchecked() }, // wake
+
+            #[no_coverage]
+            |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+
+            #[no_coverage]
+            |_| (),
+        );
+        let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+        let mut context = Context::from_waker(&waker);
+
+        loop {
+            if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+                break val;
+            }
+        }
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/issue-83601.rs b/src/test/run-make-fulldeps/coverage/issue-83601.rs
new file mode 100644
index 00000000000..0b72a81947c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/issue-83601.rs
@@ -0,0 +1,14 @@
+// Shows that rust-lang/rust/83601 is resolved
+
+#[derive(Debug, PartialEq, Eq)]
+struct Foo(u32);
+
+fn main() {
+    let bar = Foo(1);
+    assert_eq!(bar, Foo(1));
+    let baz = Foo(0);
+    assert_ne!(baz, Foo(1));
+    println!("{:?}", Foo(1));
+    println!("{:?}", bar);
+    println!("{:?}", baz);
+}
diff --git a/src/test/run-make-fulldeps/coverage/issue-84561.rs b/src/test/run-make-fulldeps/coverage/issue-84561.rs
new file mode 100644
index 00000000000..b39a289c45e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/issue-84561.rs
@@ -0,0 +1,182 @@
+// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+
+// expect-exit-status-101
+#[derive(PartialEq, Eq)]
+struct Foo(u32);
+fn test3() {
+    let is_true = std::env::args().len() == 1;
+    let bar = Foo(1);
+    assert_eq!(bar, Foo(1));
+    let baz = Foo(0);
+    assert_ne!(baz, Foo(1));
+    println!("{:?}", Foo(1));
+    println!("{:?}", bar);
+    println!("{:?}", baz);
+
+    assert_eq!(Foo(1), Foo(1));
+    assert_ne!(Foo(0), Foo(1));
+    assert_eq!(Foo(2), Foo(2));
+    let bar = Foo(0);
+    assert_ne!(bar, Foo(3));
+    assert_ne!(Foo(0), Foo(4));
+    assert_eq!(Foo(3), Foo(3), "with a message");
+    println!("{:?}", bar);
+    println!("{:?}", Foo(1));
+
+    assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+    assert_ne!(
+        Foo(0)
+        ,
+        Foo(5)
+        ,
+        "{}"
+        ,
+        if
+        is_true
+        {
+            "true message"
+        } else {
+            "false message"
+        }
+    );
+
+    let is_true = std::env::args().len() == 1;
+
+    assert_eq!(
+        Foo(1),
+        Foo(1)
+    );
+    assert_ne!(
+        Foo(0),
+        Foo(1)
+    );
+    assert_eq!(
+        Foo(2),
+        Foo(2)
+    );
+    let bar = Foo(1);
+    assert_ne!(
+        bar,
+        Foo(3)
+    );
+    if is_true {
+        assert_ne!(
+            Foo(0),
+            Foo(4)
+        );
+    } else {
+        assert_eq!(
+            Foo(3),
+            Foo(3)
+        );
+    }
+    if is_true {
+        assert_ne!(
+            Foo(0),
+            Foo(4),
+            "with a message"
+        );
+    } else {
+        assert_eq!(
+            Foo(3),
+            Foo(3),
+            "with a message"
+        );
+    }
+    assert_ne!(
+        if is_true {
+            Foo(0)
+        } else {
+            Foo(1)
+        },
+        Foo(5)
+    );
+    assert_ne!(
+        Foo(5),
+        if is_true {
+            Foo(0)
+        } else {
+            Foo(1)
+        }
+    );
+    assert_ne!(
+        if is_true {
+            assert_eq!(
+                Foo(3),
+                Foo(3)
+            );
+            Foo(0)
+        } else {
+            assert_ne!(
+                if is_true {
+                    Foo(0)
+                } else {
+                    Foo(1)
+                },
+                Foo(5)
+            );
+            Foo(1)
+        },
+        Foo(5),
+        "with a message"
+    );
+    assert_eq!(
+        Foo(1),
+        Foo(3),
+        "this assert should fail"
+    );
+    assert_eq!(
+        Foo(3),
+        Foo(3),
+        "this assert should not be reached"
+    );
+}
+
+impl std::fmt::Debug for Foo {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(f, "try and succeed")?;
+        Ok(())
+    }
+}
+
+static mut DEBUG_LEVEL_ENABLED: bool = false;
+
+macro_rules! debug {
+    ($($arg:tt)+) => (
+        if unsafe { DEBUG_LEVEL_ENABLED } {
+            println!($($arg)+);
+        }
+    );
+}
+
+fn test1() {
+    debug!("debug is enabled");
+    debug!("debug is enabled");
+    let _ = 0;
+    debug!("debug is enabled");
+    unsafe {
+        DEBUG_LEVEL_ENABLED = true;
+    }
+    debug!("debug is enabled");
+}
+
+macro_rules! call_debug {
+    ($($arg:tt)+) => (
+        fn call_print(s: &str) {
+            print!("{}", s);
+        }
+
+        call_print("called from call_debug: ");
+        debug!($($arg)+);
+    );
+}
+
+fn test2() {
+    call_debug!("debug is enabled");
+}
+
+fn main() {
+    test1();
+    test2();
+    test3();
+}
diff --git a/src/test/run-make-fulldeps/coverage/no_cov_crate.rs b/src/test/run-make-fulldeps/coverage/no_cov_crate.rs
new file mode 100644
index 00000000000..300570db7e8
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/no_cov_crate.rs
@@ -0,0 +1,17 @@
+// Enables `no_coverage` on the entire crate
+#![feature(no_coverage)]
+
+#[no_coverage]
+fn do_not_add_coverage_1() {
+    println!("called but not covered");
+}
+
+#[no_coverage]
+fn do_not_add_coverage_2() {
+    println!("called but not covered");
+}
+
+fn main() {
+    do_not_add_coverage_1();
+    do_not_add_coverage_2();
+}
diff --git a/src/test/run-make-fulldeps/coverage/no_cov_func.rs b/src/test/run-make-fulldeps/coverage/no_cov_func.rs
new file mode 100644
index 00000000000..e19a2c4a872
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/no_cov_func.rs
@@ -0,0 +1,18 @@
+// Enables `no_coverage` on individual functions
+
+#[feature(no_coverage)]
+#[no_coverage]
+fn do_not_add_coverage_1() {
+    println!("called but not covered");
+}
+
+#[no_coverage]
+#[feature(no_coverage)]
+fn do_not_add_coverage_2() {
+    println!("called but not covered");
+}
+
+fn main() {
+    do_not_add_coverage_1();
+    do_not_add_coverage_2();
+}
diff --git a/src/test/run-make-fulldeps/coverage/try_error_result.rs b/src/test/run-make-fulldeps/coverage/try_error_result.rs
index 13c455172dd..cd0acf72302 100644
--- a/src/test/run-make-fulldeps/coverage/try_error_result.rs
+++ b/src/test/run-make-fulldeps/coverage/try_error_result.rs
@@ -9,7 +9,7 @@ fn call(return_error: bool) -> Result<(),()> {
     }
 }
 
-fn main() -> Result<(),()> {
+fn test1() -> Result<(),()> {
     let mut
         countdown = 10
     ;
@@ -34,3 +34,85 @@ fn main() -> Result<(),()> {
     }
     Ok(())
 }
+
+struct Thing1;
+impl Thing1 {
+    fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
+        if return_error {
+            Err(())
+        } else {
+            Ok(Thing2{})
+        }
+    }
+}
+
+struct Thing2;
+impl Thing2 {
+    fn call(&self, return_error: bool) -> Result<u32,()> {
+        if return_error {
+            Err(())
+        } else {
+            Ok(57)
+        }
+    }
+}
+
+fn test2() -> Result<(),()> {
+    let thing1 = Thing1{};
+    let mut
+        countdown = 10
+    ;
+    for
+        _
+    in
+        0..10
+    {
+        countdown
+            -= 1
+        ;
+        if
+            countdown < 5
+        {
+            thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+            thing1
+                .
+                get_thing_2(/*return_error=*/ false)
+                ?
+                .
+                call(/*return_error=*/ true)
+                .
+                expect_err(
+                    "call should fail"
+                );
+            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+            assert_eq!(val, 57);
+            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+        }
+        else
+        {
+            let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+            let val = thing1
+                .get_thing_2(/*return_error=*/ false)?
+                .call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+            let val = thing1
+                .get_thing_2(/*return_error=*/ false)
+                ?
+                .call(/*return_error=*/ false)
+                ?
+                ;
+            assert_eq!(val, 57);
+        }
+    }
+    Ok(())
+}
+
+fn main() -> Result<(),()> {
+    test1().expect_err("test1 should fail");
+    test2()
+    ?
+    ;
+    Ok(())
+}
diff --git a/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile b/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile
index 50ff3dd56ce..371f94715a8 100644
--- a/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile
+++ b/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile
@@ -1,7 +1,7 @@
 -include ../tools.mk
 
 # rust-lang/rust#70924: Test that if we add rust-src component in between two
-# incremetnal compiles, the compiler does not ICE on the second.
+# incremental compiles, the compiler does not ICE on the second.
 
 # This test uses `ln -s` rather than copying to save testing time, but its
 # usage doesn't work on windows. So ignore windows.
diff --git a/src/test/rustdoc-ui/no-run-flag-error.rs b/src/test/rustdoc-ui/no-run-flag-error.rs
new file mode 100644
index 00000000000..4ead621482b
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag-error.rs
@@ -0,0 +1,6 @@
+// test the behavior of the --no-run flag without the --test flag
+
+// compile-flags:-Z unstable-options --no-run --test-args=--test-threads=1
+// error-pattern: the `--test` flag must be passed
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/no-run-flag-error.stderr b/src/test/rustdoc-ui/no-run-flag-error.stderr
new file mode 100644
index 00000000000..d032646c365
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag-error.stderr
@@ -0,0 +1,2 @@
+error: the `--test` flag must be passed to enable `--no-run`
+
diff --git a/src/test/rustdoc-ui/no-run-flag.rs b/src/test/rustdoc-ui/no-run-flag.rs
new file mode 100644
index 00000000000..da1672c4a6e
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag.rs
@@ -0,0 +1,38 @@
+// test the behavior of the --no-run flag
+
+// check-pass
+// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// let a = true;
+/// ```
+/// ```should_panic
+/// panic!()
+/// ```
+/// ```ignore (incomplete-code)
+/// fn foo() {
+/// ```
+/// ```no_run
+/// loop {
+///     println!("Hello, world");
+/// }
+/// ```
+/// fails to compile
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+/// Ok the test does not run
+/// ```
+/// panic!()
+/// ```
+/// Ok the test does not run
+/// ```should_panic
+/// loop {
+///     println!("Hello, world");
+/// panic!()
+/// }
+/// ```
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/no-run-flag.stdout b/src/test/rustdoc-ui/no-run-flag.stdout
new file mode 100644
index 00000000000..d92f5da8335
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag.stdout
@@ -0,0 +1,12 @@
+
+running 7 tests
+test $DIR/no-run-flag.rs - f (line 11) ... ok
+test $DIR/no-run-flag.rs - f (line 14) ... ignored
+test $DIR/no-run-flag.rs - f (line 17) ... ok
+test $DIR/no-run-flag.rs - f (line 23) ... ok
+test $DIR/no-run-flag.rs - f (line 28) ... ok
+test $DIR/no-run-flag.rs - f (line 32) ... ok
+test $DIR/no-run-flag.rs - f (line 8) ... ok
+
+test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc/auto_aliases.rs b/src/test/rustdoc/auto_aliases.rs
index b8f3527510c..56e0770ab5c 100644
--- a/src/test/rustdoc/auto_aliases.rs
+++ b/src/test/rustdoc/auto_aliases.rs
@@ -1,6 +1,6 @@
 #![feature(auto_traits)]
 
-// @has auto_aliases/trait.Bar.html '//h3[@aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
+// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
 pub struct Foo;
 
 pub auto trait Bar {}
diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs
new file mode 100644
index 00000000000..86dec32e625
--- /dev/null
+++ b/src/test/rustdoc/empty-impls.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo'
+pub struct Foo;
+
+pub trait EmptyTrait {}
+
+// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+impl EmptyTrait for Foo {}
+
+pub trait NotEmpty {
+    fn foo(&self);
+}
+
+// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+impl NotEmpty for Foo {
+    fn foo(&self) {}
+}
diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs
index daebe059f8e..ddc14e68675 100644
--- a/src/test/rustdoc/issue-53812.rs
+++ b/src/test/rustdoc/issue-53812.rs
@@ -12,9 +12,9 @@ macro_rules! array_impls {
     }
 }
 
-// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/details[1]/summary/h3' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/details[2]/summary/h3' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/details[3]/summary/h3' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/details[4]/summary/h3' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/details[5]/summary/h3' 'MyStruct<[T; 10]>'
+// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
diff --git a/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs b/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
index d8a9ae6ca20..5a6283e9f13 100644
--- a/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
+++ b/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
@@ -2,8 +2,6 @@
 
 // run-pass
 
-#![feature(const_fn)]
-
 #[derive(PartialEq, Debug, Clone)]
 struct N(u8);
 
diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs
index 18be201d640..634ef010e6f 100644
--- a/src/test/ui/asm/sym.rs
+++ b/src/test/ui/asm/sym.rs
@@ -1,6 +1,4 @@
 // min-llvm-version: 10.0.1
-// FIXME(#84025): codegen-units=1 leads to linkage errors
-// compile-flags: -C codegen-units=2
 // only-x86_64
 // only-linux
 // run-pass
diff --git a/src/test/ui/associated-consts/associated-const-in-trait.rs b/src/test/ui/associated-consts/associated-const-in-trait.rs
index cc3acd53956..f3024120df1 100644
--- a/src/test/ui/associated-consts/associated-const-in-trait.rs
+++ b/src/test/ui/associated-consts/associated-const-in-trait.rs
@@ -1,6 +1,6 @@
 // #29924
 
-#![feature(const_fn, associated_consts)]
+#![feature(associated_consts)]
 
 trait Trait {
     const N: usize;
diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
index 193026541d0..599d0e13557 100644
--- a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
+++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
@@ -21,9 +21,9 @@ error[E0373]: async block may outlive the current function, but it borrows `x`,
   --> $DIR/async-borrowck-escaping-block-error.rs:11:11
    |
 LL |     async { *x }
-   |           ^^^-^^
-   |           |  |
-   |           |  `x` is borrowed here
+   |           ^^--^^
+   |           | |
+   |           | `x` is borrowed here
    |           may outlive borrowed value `x`
    |
 note: async block is returned here
diff --git a/src/test/ui/async-await/issue-68523.rs b/src/test/ui/async-await/issue-68523.rs
index 718c597e712..7a67661a019 100644
--- a/src/test/ui/async-await/issue-68523.rs
+++ b/src/test/ui/async-await/issue-68523.rs
@@ -2,6 +2,5 @@
 
 async fn main() -> Result<i32, ()> {
 //~^ ERROR `main` function is not allowed to be `async`
-//~^^ ERROR `main` has invalid return type `impl Future`
     Ok(1)
 }
diff --git a/src/test/ui/async-await/issue-68523.stderr b/src/test/ui/async-await/issue-68523.stderr
index 6f67af04cd4..dfdf078e303 100644
--- a/src/test/ui/async-await/issue-68523.stderr
+++ b/src/test/ui/async-await/issue-68523.stderr
@@ -1,18 +1,9 @@
-error[E0277]: `main` has invalid return type `impl Future`
-  --> $DIR/issue-68523.rs:3:20
-   |
-LL | async fn main() -> Result<i32, ()> {
-   |                    ^^^^^^^^^^^^^^^ `main` can only return types that implement `Termination`
-   |
-   = help: consider using `()`, or a `Result`
-
 error[E0752]: `main` function is not allowed to be `async`
   --> $DIR/issue-68523.rs:3:1
    |
 LL | async fn main() -> Result<i32, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0277, E0752.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0752`.
diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr
index edeb21c16d3..fadcd11a592 100644
--- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr
@@ -73,7 +73,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/borrowck-closures-mut-and-imm.rs:57:5
    |
 LL |     let c1 = || get(&*x);
-   |              --       - borrow occurs due to use in closure
+   |              --      -- borrow occurs due to use in closure
    |              |
    |              borrow of `*x` occurs here
 LL |     *x = 5;
@@ -86,7 +86,7 @@ error[E0506]: cannot assign to `*x.f` because it is borrowed
   --> $DIR/borrowck-closures-mut-and-imm.rs:69:5
    |
 LL |     let c1 = || get(&*x.f);
-   |              --       - borrow occurs due to use in closure
+   |              --      ---- borrow occurs due to use in closure
    |              |
    |              borrow of `*x.f` occurs here
 LL |     *x.f = 5;
@@ -99,11 +99,11 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/borrowck-closures-mut-and-imm.rs:81:14
    |
 LL |     let c1 = || get(&*x.f);
-   |              --       - first borrow occurs due to use of `x` in closure
+   |              --      ---- first borrow occurs due to use of `x` in closure
    |              |
    |              immutable borrow occurs here
 LL |     let c2 = || *x.f = 5;
-   |              ^^  - second borrow occurs due to use of `x` in closure
+   |              ^^ ---- second borrow occurs due to use of `x` in closure
    |              |
    |              mutable borrow occurs here
 LL |
diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr
index 784b903a589..537ec9895e1 100644
--- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr
@@ -14,12 +14,12 @@ error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/borrowck-closures-mut-of-imm.rs:11:18
    |
 LL |     let mut c1 = || set(&mut *x);
-   |                  --           - first borrow occurs due to use of `x` in closure
+   |                  --          -- first borrow occurs due to use of `x` in closure
    |                  |
    |                  first closure is constructed here
 LL |
 LL |     let mut c2 = || set(&mut *x);
-   |                  ^^           - second borrow occurs due to use of `x` in closure
+   |                  ^^          -- second borrow occurs due to use of `x` in closure
    |                  |
    |                  second closure is constructed here
 ...
diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr
index 471173e595f..e5ee5a40105 100644
--- a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr
@@ -2,11 +2,11 @@ error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/borrowck-closures-mut-of-mut.rs:14:18
    |
 LL |     let mut c1 = || set(&mut *x);
-   |                  --           - first borrow occurs due to use of `x` in closure
+   |                  --          -- first borrow occurs due to use of `x` in closure
    |                  |
    |                  first closure is constructed here
 LL |     let mut c2 = || set(&mut *x);
-   |                  ^^           - second borrow occurs due to use of `x` in closure
+   |                  ^^          -- second borrow occurs due to use of `x` in closure
    |                  |
    |                  second closure is constructed here
 LL |
diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr
index 9e1e47a9241..411d85b8e05 100644
--- a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr
@@ -45,7 +45,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut
 LL |     let f = || {
    |             -- immutable borrow occurs here
 LL |         let [ref y, ref z @ ..] = *x;
-   |                                    - first borrow occurs due to use of `x` in closure
+   |                                   -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &mut *x;
    |             ^^^^^^^ mutable borrow occurs here
@@ -59,7 +59,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
 LL |     let mut f = || {
    |                 -- closure construction occurs here
 LL |         let [ref mut y, ref mut z @ ..] = *x;
-   |                                            - first borrow occurs due to use of `x` in closure
+   |                                           -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &x;
    |             ^^ second borrow occurs here
@@ -86,7 +86,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut
 LL |     let f = || {
    |             -- immutable borrow occurs here
 LL |         if let [ref y, ref z @ ..] = *x {}
-   |                                       - first borrow occurs due to use of `x` in closure
+   |                                      -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &mut *x;
    |             ^^^^^^^ mutable borrow occurs here
@@ -100,7 +100,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
 LL |     let mut f = || {
    |                 -- closure construction occurs here
 LL |         if let [ref mut y, ref mut z @ ..] = *x {}
-   |                                               - first borrow occurs due to use of `x` in closure
+   |                                              -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &x;
    |             ^^ second borrow occurs here
diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr
index 07f477d1786..fe8e7a29e24 100644
--- a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr
@@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-closures-two-mut-fail.rs:53:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
-   |                        --           - first borrow occurs due to use of `x` in closure
+   |                        --          ---- first borrow occurs due to use of `x` in closure
    |                        |
    |                        first mutable borrow occurs here
 LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
-   |                        ^^           - second borrow occurs due to use of `x` in closure
+   |                        ^^          ---- second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
 LL |
diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
index bffb1164074..21e329f4329 100644
--- a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
@@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-closures-two-mut.rs:49:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
-   |                        --           - first borrow occurs due to use of `x` in closure
+   |                        --          ---- first borrow occurs due to use of `x` in closure
    |                        |
    |                        first mutable borrow occurs here
 LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
-   |                        ^^           - second borrow occurs due to use of `x` in closure
+   |                        ^^          ---- second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
 LL |
diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr
index 64c2f419ffa..23d3cc0e76f 100644
--- a/src/test/ui/borrowck/borrowck-closures-unique.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr
@@ -20,7 +20,7 @@ LL |     let c1 = || get(x);
    |              |
    |              borrow occurs here
 LL |     let c2 = || { get(x); set(x); };
-   |              ^^       - second borrow occurs due to use of `x` in closure
+   |              ^^               - second borrow occurs due to use of `x` in closure
    |              |
    |              closure construction occurs here
 LL |     c1;
diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr
index f22b7da8119..a6dbcf36077 100644
--- a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr
@@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m
 LL |   let mut test = |foo: &Foo| {
    |                  ----------- mutable borrow occurs here
 LL |     ptr = box Foo { x: ptr.x + 1 };
-   |                        --- first borrow occurs due to use of `ptr` in closure
+   |     --- first borrow occurs due to use of `ptr` in closure
 LL |   };
 LL |   test(&*ptr);
    |   ---- ^^^^^ immutable borrow occurs here
diff --git a/src/test/ui/borrowck/borrowck-insert-during-each.stderr b/src/test/ui/borrowck/borrowck-insert-during-each.stderr
index 796390c093b..a1ac45795fa 100644
--- a/src/test/ui/borrowck/borrowck-insert-during-each.stderr
+++ b/src/test/ui/borrowck/borrowck-insert-during-each.stderr
@@ -9,7 +9,7 @@ LL | |
 LL | |         |a| {
    | |         --- closure construction occurs here
 LL | |             f.n.insert(*a);
-   | |             - first borrow occurs due to use of `f` in closure
+   | |             --- first borrow occurs due to use of `f` in closure
 LL | |         })
    | |__________^ second borrow occurs here
 
@@ -24,7 +24,7 @@ LL |
 LL |         |a| {
    |         ^^^ closure construction occurs here
 LL |             f.n.insert(*a);
-   |             - second borrow occurs due to use of `f` in closure
+   |             --- second borrow occurs due to use of `f` in closure
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
index 2acbcd94f8b..ac25502ad05 100644
--- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
+++ b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
@@ -7,7 +7,7 @@ LL |     thread::spawn(move|| {
    |                   ^^^^^^ move out of `v` occurs here
 LL |
 LL |         println!("v={}", *v);
-   |                           - move occurs due to use in closure
+   |                          -- move occurs due to use in closure
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
@@ -21,7 +21,7 @@ LL |     thread::spawn(move|| {
    |                   ^^^^^^ move out of `v` occurs here
 LL |
 LL |         println!("v={}", *v);
-   |                           - move occurs due to use in closure
+   |                          -- move occurs due to use in closure
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr
index ec3edc80323..489ec7d04ed 100644
--- a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr
+++ b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr
@@ -7,7 +7,7 @@ LL |     p.blockm(|| {
    |     | immutable borrow later used by call
    |     immutable borrow occurs here
 LL |         p.x = 10;
-   |         - second borrow occurs due to use of `p` in closure
+   |         --- second borrow occurs due to use of `p` in closure
 
 error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-loan-rcvr.rs:34:5
diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
index 837bd08253b..628f206e0a8 100644
--- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr
+++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
@@ -5,10 +5,10 @@ LL |     let bar: Box<_> = box 3;
    |         --- captured outer variable
 LL |     let _g = to_fn_mut(|| {
 LL |         let _h = to_fn_once(move || -> isize { *bar });
-   |                             ^^^^^^^^^^^^^^^^    ---
-   |                             |                   |
-   |                             |                   move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
-   |                             |                   move occurs due to use in closure
+   |                             ^^^^^^^^^^^^^^^^   ----
+   |                             |                  |
+   |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+   |                             |                  move occurs due to use in closure
    |                             move out of `bar` occurs here
 
 error: aborting due to previous error
diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr
index 44f423c2bd9..1ac4999e6e1 100644
--- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr
+++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr
@@ -5,11 +5,11 @@ LL |     let t: Box<_> = box 3;
    |         - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait
 LL | 
 LL |     call_f(move|| { *t + 1 });
-   |            ------    - variable moved due to use in closure
+   |            ------   -- variable moved due to use in closure
    |            |
    |            value moved into closure here
 LL |     call_f(move|| { *t + 1 });
-   |            ^^^^^^    - use occurs due to use in closure
+   |            ^^^^^^   -- use occurs due to use in closure
    |            |
    |            value used here after move
 
diff --git a/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr
index f0a3151f4e1..dd46308d140 100644
--- a/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr
+++ b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr
@@ -5,7 +5,7 @@ LL |     match x {
    |           - value is immutable in match guard
 ...
 LL |                 (|| { *x = None; drop(force_fn_once); })();
-   |                  ^^    - borrow occurs due to use of `x` in closure
+   |                  ^^   -- borrow occurs due to use of `x` in closure
    |                  |
    |                  cannot mutably borrow
 
diff --git a/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr
index f0264b56ea5..48433432de1 100644
--- a/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr
+++ b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr
@@ -2,7 +2,7 @@ error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern g
   --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
    |
 LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
-   |                         ^^                   - mutable borrow occurs due to use of `r` in closure
+   |                         ^^                  -- mutable borrow occurs due to use of `r` in closure
    |                         |
    |                         cannot borrow as mutable
    |
diff --git a/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs
new file mode 100644
index 00000000000..6da88bed2c6
--- /dev/null
+++ b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs
@@ -0,0 +1,32 @@
+// rust-lang/rust#83309: The compiler tries to suggest potential
+// methods that return `&mut` items. However, when it doesn't
+// find such methods, it still tries to add suggestions
+// which then fails an assertion later because there was
+// no suggestions to make.
+
+
+fn main() {
+    for v in Query.iter_mut() {
+        //~^ NOTE this iterator yields `&` references
+        *v -= 1;
+        //~^ ERROR cannot assign to `*v` which is behind a `&` reference
+        //~| NOTE `v` is a `&` reference, so the data it refers to cannot be written
+    }
+}
+
+pub struct Query;
+pub struct QueryIter<'a>(&'a i32);
+
+impl Query {
+    pub fn iter_mut<'a>(&'a mut self) -> QueryIter<'a> {
+        todo!();
+    }
+}
+
+impl<'a> Iterator for QueryIter<'a> {
+    type Item = &'a i32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        todo!();
+    }
+}
diff --git a/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr
new file mode 100644
index 00000000000..143b74c39ba
--- /dev/null
+++ b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr
@@ -0,0 +1,12 @@
+error[E0594]: cannot assign to `*v` which is behind a `&` reference
+  --> $DIR/issue-83309-ice-immut-in-for-loop.rs:11:9
+   |
+LL |     for v in Query.iter_mut() {
+   |              ---------------- this iterator yields `&` references
+LL |
+LL |         *v -= 1;
+   |         ^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs
new file mode 100644
index 00000000000..2f3358dcd8d
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs
@@ -0,0 +1,20 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+fn main() {
+    let mut p = Point {x: 1, y: 2 };
+
+    let y = &mut p.y;
+    let mut c = || {
+    //~^ ERROR cannot borrow `p` as mutable more than once at a time
+       let x = &mut p.x;
+       println!("{:?}", p);
+    };
+    c();
+    *y+=1;
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr
new file mode 100644
index 00000000000..e15067b264d
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr
@@ -0,0 +1,28 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-1.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0499]: cannot borrow `p` as mutable more than once at a time
+  --> $DIR/borrowck-1.rs:13:17
+   |
+LL |     let y = &mut p.y;
+   |             -------- first mutable borrow occurs here
+LL |     let mut c = || {
+   |                 ^^ second mutable borrow occurs here
+LL |
+LL |        let x = &mut p.x;
+   |                     --- capture is mutable because of use here
+LL |        println!("{:?}", p);
+   |                         - second borrow occurs due to use of `p` in closure
+...
+LL |     *y+=1;
+   |     ----- first borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs
new file mode 100644
index 00000000000..06c6a87eb10
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs
@@ -0,0 +1,20 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+fn main() {
+    let mut p = Point {x: 1, y: 2 };
+
+    let y = &p.y;
+    let mut c = || {
+    //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+       println!("{:?}", p);
+       let x = &mut p.x;
+    };
+    c();
+    println!("{}", y);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr
new file mode 100644
index 00000000000..a195b981eaa
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr
@@ -0,0 +1,28 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-2.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-2.rs:13:17
+   |
+LL |     let y = &p.y;
+   |             ---- immutable borrow occurs here
+LL |     let mut c = || {
+   |                 ^^ mutable borrow occurs here
+LL |
+LL |        println!("{:?}", p);
+   |                         - second borrow occurs due to use of `p` in closure
+LL |        let x = &mut p.x;
+   |                     --- capture is mutable because of use here
+...
+LL |     println!("{}", y);
+   |                    - immutable borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs
new file mode 100644
index 00000000000..ba998f78c87
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs
@@ -0,0 +1,19 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: String,
+    y: String,
+}
+fn main() {
+    let mut c = {
+        let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+        || {
+           let x = &mut p.x;
+           println!("{:?}", p);
+            //~^ ERROR `p` does not live long enough
+        }
+    };
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr
new file mode 100644
index 00000000000..b54c729a307
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr
@@ -0,0 +1,27 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-3.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0597]: `p` does not live long enough
+  --> $DIR/borrowck-3.rs:14:29
+   |
+LL |     let mut c = {
+   |         ----- borrow later stored here
+LL |         let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+LL |         || {
+   |         -- value captured here
+LL |            let x = &mut p.x;
+LL |            println!("{:?}", p);
+   |                             ^ borrowed value does not live long enough
+...
+LL |     };
+   |     - `p` dropped here while still borrowed
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs
new file mode 100644
index 00000000000..4fab0189c27
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs
@@ -0,0 +1,21 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+fn foo () -> impl FnMut()->() {
+    let mut p = Point {x: 1, y: 2 };
+    let mut c = || {
+    //~^ ERROR closure may outlive the current function, but it borrows `p`
+       p.x+=5;
+       println!("{:?}", p);
+    };
+    c
+}
+fn main() {
+    let c = foo();
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
new file mode 100644
index 00000000000..905fa3475ed
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
@@ -0,0 +1,31 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-4.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0373]: closure may outlive the current function, but it borrows `p`, which is owned by the current function
+  --> $DIR/borrowck-4.rs:11:17
+   |
+LL |     let mut c = || {
+   |                 ^^ may outlive borrowed value `p`
+...
+LL |        println!("{:?}", p);
+   |                         - `p` is borrowed here
+   |
+note: closure is returned here
+  --> $DIR/borrowck-4.rs:9:14
+   |
+LL | fn foo () -> impl FnMut()->() {
+   |              ^^^^^^^^^^^^^^^^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+   |
+LL |     let mut c = move || {
+   |                 ^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs
new file mode 100644
index 00000000000..b23947ad5d1
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs
@@ -0,0 +1,26 @@
+// Tests that two closures cannot simultaneously have mutable
+// and immutable access to the variable. Issue #6801.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+#![feature(box_syntax)]
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn a() {
+    let mut p = Point {x: 3, y:4};
+    let c2 = || p.y * 5;
+    let c1 = || {
+    //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+        dbg!(&p);
+        p.x = 4;
+    };
+    drop(c2);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr
new file mode 100644
index 00000000000..58975c6f46f
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr
@@ -0,0 +1,30 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-closures-mut-and-imm.rs:4:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-closures-mut-and-imm.rs:17:14
+   |
+LL |     let c2 = || p.y * 5;
+   |              -- --- first borrow occurs due to use of `p.y` in closure
+   |              |
+   |              immutable borrow occurs here
+LL |     let c1 = || {
+   |              ^^ mutable borrow occurs here
+LL |
+LL |         dbg!(&p);
+   |               - second borrow occurs due to use of `p` in closure
+LL |         p.x = 4;
+   |         --- capture is mutable because of use here
+LL |     };
+LL |     drop(c2);
+   |          -- immutable borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
index 17a9332fb3e..174faa33c49 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
@@ -13,7 +13,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
 LL |     let mut c = || {
    |                 -- borrow of `e.0.0.m.x` occurs here
 LL |         e.0.0.m.x = format!("not-x");
-   |         - borrow occurs due to use in closure
+   |         --------- borrow occurs due to use in closure
 ...
 LL |     e.0.0.m.x = format!("not-x");
    |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
@@ -27,7 +27,7 @@ error[E0502]: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed
 LL |     let mut c = || {
    |                 -- mutable borrow occurs here
 LL |         e.0.0.m.x = format!("not-x");
-   |         - first borrow occurs due to use of `e.0.0.m.x` in closure
+   |         --------- first borrow occurs due to use of `e.0.0.m.x` in closure
 ...
 LL |     println!("{}", e.0.0.m.x);
    |                    ^^^^^^^^^ immutable borrow occurs here
@@ -41,7 +41,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
 LL |     let c = || {
    |             -- borrow of `e.0.0.m.x` occurs here
 LL |         println!("{}", e.0.0.m.x);
-   |                        - borrow occurs due to use in closure
+   |                        --------- borrow occurs due to use in closure
 ...
 LL |     e.0.0.m.x = format!("not-x");
    |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
index 861bc44b78d..39a11fb3327 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
@@ -14,7 +14,7 @@ LL |     let mut c = || {
    |                 ^^ cannot borrow as mutable
 LL |
 LL |         z.0.0.0 = format!("X1");
-   |         - mutable borrow occurs due to use of `z.0.0.0` in closure
+   |         ------- mutable borrow occurs due to use of `z.0.0.0` in closure
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
index 997ecc7dddd..928c866726f 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
@@ -11,7 +11,7 @@ fn mut_error_struct() {
 
     let mut c = || {
         z.0.0.0 = 20;
-        //~^ ERROR: cannot assign to `z`, as it is not declared as mutable
+        //~^ ERROR: cannot assign to `z.0.0.0`, as it is not declared as mutable
     };
 
     c();
@@ -23,7 +23,7 @@ fn mut_error_box() {
 
     let mut c = || {
         bx.0 = 20;
-        //~^ ERROR: cannot assign to `bx`, as it is not declared as mutable
+        //~^ ERROR: cannot assign to `*bx.0`, as it is not declared as mutable
     };
 
     c();
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
index 5e15635ac6e..9fb8dd4a1c3 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
@@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
 
-error[E0594]: cannot assign to `z`, as it is not declared as mutable
+error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable
   --> $DIR/cant-mutate-imm.rs:13:9
    |
 LL |     let z = (y, 10);
@@ -16,7 +16,7 @@ LL |     let z = (y, 10);
 LL |         z.0.0.0 = 20;
    |         ^^^^^^^^^^^^ cannot assign
 
-error[E0594]: cannot assign to `bx`, as it is not declared as mutable
+error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable
   --> $DIR/cant-mutate-imm.rs:25:9
    |
 LL |     let bx = Box::new(x);
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr
index e5a396c4e98..a3d1f550557 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr
@@ -13,7 +13,7 @@ error[E0499]: cannot borrow `w.p.x` as mutable more than once at a time
 LL |     let mut c = || {
    |                 -- first mutable borrow occurs here
 LL |         w.p.x += 20;
-   |         - first borrow occurs due to use of `w.p.x` in closure
+   |         ----- first borrow occurs due to use of `w.p.x` in closure
 ...
 LL |     let py = &mut w.p.x;
    |              ^^^^^^^^^^ second mutable borrow occurs here
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
index 8cb2ed2235d..831e486db82 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
@@ -17,7 +17,7 @@ LL |     let c = || {
    |             ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
 LL |
 LL |         **ref_mref_x = y;
-   |           ---------- mutable borrow occurs due to use of `**ref_mref_x` in closure
+   |         ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure
 
 error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
   --> $DIR/mut_ref.rs:27:13
@@ -26,7 +26,7 @@ LL |     let c = || {
    |             ^^ cannot borrow as mutable
 LL |
 LL |         **mref_ref_x = y;
-   |           ---------- mutable borrow occurs due to use of `**mref_ref_x` in closure
+   |         ------------ mutable borrow occurs due to use of `**mref_ref_x` in closure
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
index 45a61cd98b1..f1748fda151 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
@@ -13,7 +13,9 @@ error[E0502]: cannot borrow `p` as immutable because it is also borrowed as muta
 LL |     let mut c = || {
    |                 -- mutable borrow occurs here
 LL |         p.x += 10;
-   |         - first borrow occurs due to use of `p` in closure
+   |         --- capture is mutable because of use here
+LL |         println!("{:?}", p);
+   |                          - first borrow occurs due to use of `p` in closure
 ...
 LL |     println!("{:?}", p);
    |                      ^ immutable borrow occurs here
diff --git a/src/test/ui/const-generics/issues/issue-83466.rs b/src/test/ui/const-generics/issues/issue-83466.rs
new file mode 100644
index 00000000000..c488a663fbb
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83466.rs
@@ -0,0 +1,17 @@
+// regression test for #83466- tests that generic arg mismatch errors between
+// consts and types are not supressed when there are explicit late bound lifetimes
+
+struct S;
+impl S {
+    fn func<'a, U>(self) -> U {
+        todo!()
+    }
+}
+fn dont_crash<'a, U>() {
+    S.func::<'a, 10_u32>()
+    //~^ WARNING cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+    //~^^ WARNING this was previously accepted by
+    //~^^^ ERROR constant provided when a type was expected [E0747]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-83466.stderr b/src/test/ui/const-generics/issues/issue-83466.stderr
new file mode 100644
index 00000000000..a60f71ea614
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83466.stderr
@@ -0,0 +1,22 @@
+warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/issue-83466.rs:11:14
+   |
+LL |     fn func<'a, U>(self) -> U {
+   |             -- the late bound lifetime parameter is introduced here
+...
+LL |     S.func::<'a, 10_u32>()
+   |              ^^
+   |
+   = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-83466.rs:11:18
+   |
+LL |     S.func::<'a, 10_u32>()
+   |                  ^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/consts/const-eval/auxiliary/stability.rs b/src/test/ui/consts/const-eval/auxiliary/stability.rs
index 70531114f21..e6159551860 100644
--- a/src/test/ui/consts/const-eval/auxiliary/stability.rs
+++ b/src/test/ui/consts/const-eval/auxiliary/stability.rs
@@ -3,7 +3,6 @@
 #![crate_type="rlib"]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.rs b/src/test/ui/consts/const-eval/const_fn_ptr.rs
index 045fe9ad11a..b3c677c6984 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr.rs
+++ b/src/test/ui/consts/const-eval/const_fn_ptr.rs
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags: -Zunleash-the-miri-inside-of-you
-#![feature(const_fn)]
 
 fn double(x: usize) -> usize { x * 2 }
 const fn double_const(x: usize) -> usize { x * 2 }
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
index ab18020056b..a16ac7b2a24 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
@@ -1,27 +1,27 @@
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr.rs:12:5
+  --> $DIR/const_fn_ptr.rs:11:5
    |
 LL |     X(x)
    |     ^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr.rs:16:5
+  --> $DIR/const_fn_ptr.rs:15:5
    |
 LL |     X_CONST(x)
    |     ^^^^^^^^^^
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:19:14
+  --> $DIR/const_fn_ptr.rs:18:14
    |
 LL | const fn foo(x: fn(usize) -> usize, y: usize)  -> usize {
    |              ^
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:20:5
+  --> $DIR/const_fn_ptr.rs:19:5
    |
 LL |     x(y)
    |     ^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr.rs:20:5
+  --> $DIR/const_fn_ptr.rs:19:5
    |
 LL |     x(y)
    |     ^^^^
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs
index 14bd6558e7f..1896eba82f2 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags: -Zunleash-the-miri-inside-of-you
-#![feature(const_fn)]
 #![allow(unused)]
 
 fn double(x: usize) -> usize { x * 2 }
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr
index 0a7182fd39c..ec5de575906 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr
@@ -1,7 +1,7 @@
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr_fail.rs:10:5
+  --> $DIR/const_fn_ptr_fail.rs:9:5
    |
 LL |     X(x) // FIXME: this should error someday
    |     ^^^^
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
index 0a2532973f4..804ebf66008 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
@@ -1,7 +1,6 @@
 // build-fail
 // compile-flags: -Zunleash-the-miri-inside-of-you
 
-#![feature(const_fn)]
 #![allow(const_err)]
 
 fn double(x: usize) -> usize {
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index 2afedf30563..4f7a771f418 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -1,11 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_fn_ptr_fail2.rs:20:16
+  --> $DIR/const_fn_ptr_fail2.rs:19:16
    |
 LL |     assert_eq!(Y, 4);
    |                ^ referenced constant has errors
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_fn_ptr_fail2.rs:22:16
+  --> $DIR/const_fn_ptr_fail2.rs:21:16
    |
 LL |     assert_eq!(Z, 4);
    |                ^ referenced constant has errors
@@ -13,17 +13,17 @@ LL |     assert_eq!(Z, 4);
 warning: skipping const checks
    |
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:12:14
+  --> $DIR/const_fn_ptr_fail2.rs:11:14
    |
 LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
    |              ^
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:13:5
+  --> $DIR/const_fn_ptr_fail2.rs:12:5
    |
 LL |     x(y)
    |     ^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr_fail2.rs:13:5
+  --> $DIR/const_fn_ptr_fail2.rs:12:5
    |
 LL |     x(y)
    |     ^^^^
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
index 3729285956b..4b3cf70739c 100644
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
+++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
@@ -3,7 +3,6 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
index ca80a9ab391..69e3ca716a9 100644
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
+++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
@@ -1,5 +1,5 @@
 error: `foo` is not yet stable as a const fn
-  --> $DIR/dont_promote_unstable_const_fn.rs:15:25
+  --> $DIR/dont_promote_unstable_const_fn.rs:14:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
@@ -7,7 +7,7 @@ LL | const fn bar() -> u32 { foo() }
    = help: add `#![feature(foo)]` to the crate attributes to enable
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/dont_promote_unstable_const_fn.rs:18:28
+  --> $DIR/dont_promote_unstable_const_fn.rs:17:28
    |
 LL |     let _: &'static u32 = &foo();
    |            ------------    ^^^^^ creates a temporary which is freed while still in use
@@ -17,7 +17,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/dont_promote_unstable_const_fn.rs:22:28
+  --> $DIR/dont_promote_unstable_const_fn.rs:21:28
    |
 LL |     let _: &'static u32 = &meh();
    |            ------------    ^^^^^ creates a temporary which is freed while still in use
@@ -28,7 +28,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/dont_promote_unstable_const_fn.rs:23:26
+  --> $DIR/dont_promote_unstable_const_fn.rs:22:26
    |
 LL |     let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
    |            ----------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
diff --git a/src/test/ui/consts/const-eval/double_promotion.rs b/src/test/ui/consts/const-eval/double_promotion.rs
index 48f4426d9cf..9ee2777a647 100644
--- a/src/test/ui/consts/const-eval/double_promotion.rs
+++ b/src/test/ui/consts/const-eval/double_promotion.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_fn, rustc_attrs)]
+#![feature(rustc_attrs)]
 
 #[rustc_args_required_const(0)]
 pub const fn a(value: u8) -> u8 {
diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs
index 3f7bab06586..26162aa6228 100644
--- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs
+++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs
@@ -1,5 +1,3 @@
-#![feature(const_fn)]
-
 fn main() {}
 
 #[repr(C)]
diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr
index 4c8492b22f6..bc3b6aa6653 100644
--- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr
+++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr
@@ -1,5 +1,5 @@
 error[E0658]: unions in const fn are unstable
-  --> $DIR/feature-gate-const_fn_union.rs:12:5
+  --> $DIR/feature-gate-const_fn_union.rs:10:5
    |
 LL |     Foo { u }.i
    |     ^^^^^^^^^^^
diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs
index 3edd4e08686..1a99c77c6dd 100644
--- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs
+++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn, const_fn_union)]
+#![feature(const_fn_union)]
 
 #![allow(const_err)]
 
diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs
index 7887e426534..c9e4871bb7c 100644
--- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs
+++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn, const_fn_union)]
+#![feature(const_fn_union)]
 
 #![deny(const_err)]
 
diff --git a/src/test/ui/consts/const-eval/simd/insert_extract.rs b/src/test/ui/consts/const-eval/simd/insert_extract.rs
index 9e5cb0d4eb1..cae8fcf1068 100644
--- a/src/test/ui/consts/const-eval/simd/insert_extract.rs
+++ b/src/test/ui/consts/const-eval/simd/insert_extract.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(const_fn)]
 #![feature(repr_simd)]
 #![feature(platform_intrinsics)]
 #![feature(staged_api)]
diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.rs b/src/test/ui/consts/const-eval/union-const-eval-field.rs
index f8e1d6d569d..80263718330 100644
--- a/src/test/ui/consts/const-eval/union-const-eval-field.rs
+++ b/src/test/ui/consts/const-eval/union-const-eval-field.rs
@@ -1,5 +1,4 @@
 // only-x86_64
-#![feature(const_fn)]
 
 type Field1 = i32;
 type Field2 = f32;
diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.stderr b/src/test/ui/consts/const-eval/union-const-eval-field.stderr
index c1c2dcb2269..e5a107ff011 100644
--- a/src/test/ui/consts/const-eval/union-const-eval-field.stderr
+++ b/src/test/ui/consts/const-eval/union-const-eval-field.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-const-eval-field.rs:29:5
+  --> $DIR/union-const-eval-field.rs:28:5
    |
 LL |     const FIELD3: Field3 = unsafe { UNION.field3 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
diff --git a/src/test/ui/consts/const-eval/union-ice.rs b/src/test/ui/consts/const-eval/union-ice.rs
index 40e5a005ba4..4189619b2aa 100644
--- a/src/test/ui/consts/const-eval/union-ice.rs
+++ b/src/test/ui/consts/const-eval/union-ice.rs
@@ -1,5 +1,4 @@
 // only-x86_64
-#![feature(const_fn)]
 
 type Field1 = i32;
 type Field3 = i64;
diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr
index f8b9478ad1a..6d44b3c8b28 100644
--- a/src/test/ui/consts/const-eval/union-ice.stderr
+++ b/src/test/ui/consts/const-eval/union-ice.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-ice.rs:15:1
+  --> $DIR/union-ice.rs:14:1
    |
 LL | const FIELD3: Field3 = unsafe { UNION.field3 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
@@ -10,7 +10,7 @@ LL | const FIELD3: Field3 = unsafe { UNION.field3 };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-ice.rs:17:1
+  --> $DIR/union-ice.rs:16:1
    |
 LL | / const FIELD_PATH: Struct = Struct {
 LL | |     a: 42,
@@ -24,7 +24,7 @@ LL | | };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-ice.rs:27:1
+  --> $DIR/union-ice.rs:26:1
    |
 LL | / const FIELD_PATH2: Struct2 = Struct2 {
 LL | |     b: [
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
index bb91b43e20b..e25abab7e37 100644
--- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
@@ -1,18 +1,18 @@
 warning: any use of this value will cause an error
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              transmuting to uninhabited type
-   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:6:14
-   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:16:26
+   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:5:14
+   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:15:26
 ...
 LL | const FOO: [Empty; 3] = [foo(); 3];
    | -----------------------------------
    |
 note: the lint level is defined here
-  --> $DIR/validate_uninhabited_zsts.rs:15:8
+  --> $DIR/validate_uninhabited_zsts.rs:14:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
@@ -20,7 +20,7 @@ LL | #[warn(const_err)]
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:19:1
+  --> $DIR/validate_uninhabited_zsts.rs:18:1
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
@@ -29,7 +29,7 @@ LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    = note: the raw bytes of the constant (size: 0, align: 1) {}
 
 warning: the type `!` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     unsafe { std::mem::transmute(()) }
    = note: the `!` type has no valid value
 
 warning: the type `Empty` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:19:35
+  --> $DIR/validate_uninhabited_zsts.rs:18:35
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
index bb91b43e20b..e25abab7e37 100644
--- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
@@ -1,18 +1,18 @@
 warning: any use of this value will cause an error
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              transmuting to uninhabited type
-   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:6:14
-   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:16:26
+   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:5:14
+   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:15:26
 ...
 LL | const FOO: [Empty; 3] = [foo(); 3];
    | -----------------------------------
    |
 note: the lint level is defined here
-  --> $DIR/validate_uninhabited_zsts.rs:15:8
+  --> $DIR/validate_uninhabited_zsts.rs:14:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
@@ -20,7 +20,7 @@ LL | #[warn(const_err)]
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:19:1
+  --> $DIR/validate_uninhabited_zsts.rs:18:1
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
@@ -29,7 +29,7 @@ LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    = note: the raw bytes of the constant (size: 0, align: 1) {}
 
 warning: the type `!` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     unsafe { std::mem::transmute(()) }
    = note: the `!` type has no valid value
 
 warning: the type `Empty` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:19:35
+  --> $DIR/validate_uninhabited_zsts.rs:18:35
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
index a32dfa2918b..112ace5e97f 100644
--- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
@@ -1,5 +1,4 @@
 // stderr-per-bitwidth
-#![feature(const_fn)]
 #![feature(const_fn_transmute)]
 
 const fn foo() -> ! {
diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/ui/consts/const-fn-error.rs
index 68a4d414ff3..b9c5a0e040d 100644
--- a/src/test/ui/consts/const-fn-error.rs
+++ b/src/test/ui/consts/const-fn-error.rs
@@ -1,5 +1,3 @@
-#![feature(const_fn)]
-
 const X : usize = 2;
 
 const fn f(x: usize) -> usize {
diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr
index 86b1eebcb2c..f5e69bba4c5 100644
--- a/src/test/ui/consts/const-fn-error.stderr
+++ b/src/test/ui/consts/const-fn-error.stderr
@@ -1,5 +1,5 @@
 error[E0744]: `for` is not allowed in a `const fn`
-  --> $DIR/const-fn-error.rs:7:5
+  --> $DIR/const-fn-error.rs:5:5
    |
 LL | /     for i in 0..x {
 LL | |
@@ -11,13 +11,13 @@ LL | |     }
    | |_____^
 
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
@@ -26,22 +26,22 @@ LL |     for i in 0..x {
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
    |              |
    |              calling non-const function `<std::ops::Range<usize> as IntoIterator>::into_iter`
-   |              inside `f` at $DIR/const-fn-error.rs:7:14
+   |              inside `f` at $DIR/const-fn-error.rs:5:14
 ...
 LL |     let a : [i32; f(X)];
-   |                   ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:20:19
+   |                   ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:18:19
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/consts/const-fn-mismatch.rs b/src/test/ui/consts/const-fn-mismatch.rs
index d4cfba6460c..3107b8128e6 100644
--- a/src/test/ui/consts/const-fn-mismatch.rs
+++ b/src/test/ui/consts/const-fn-mismatch.rs
@@ -3,8 +3,6 @@
 // it if the trait fn is const (but right now no trait fns can be
 // const).
 
-#![feature(const_fn)]
-
 trait Foo {
     fn f() -> u32;
 }
diff --git a/src/test/ui/consts/const-fn-mismatch.stderr b/src/test/ui/consts/const-fn-mismatch.stderr
index 0f4ce010fee..a86a06b3ef1 100644
--- a/src/test/ui/consts/const-fn-mismatch.stderr
+++ b/src/test/ui/consts/const-fn-mismatch.stderr
@@ -1,5 +1,5 @@
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/const-fn-mismatch.rs:13:5
+  --> $DIR/const-fn-mismatch.rs:11:5
    |
 LL |     const fn f() -> u32 {
    |     ^^^^^ functions in traits cannot be const
diff --git a/src/test/ui/consts/const-fn-not-in-trait.rs b/src/test/ui/consts/const-fn-not-in-trait.rs
index cbc220a1ba2..00bae3f3b99 100644
--- a/src/test/ui/consts/const-fn-not-in-trait.rs
+++ b/src/test/ui/consts/const-fn-not-in-trait.rs
@@ -1,8 +1,6 @@
 // Test that const fn is illegal in a trait declaration, whether or
 // not a default is provided, and even with the feature gate.
 
-#![feature(const_fn)]
-
 trait Foo {
     const fn f() -> u32;
     //~^ ERROR functions in traits cannot be declared const
diff --git a/src/test/ui/consts/const-fn-not-in-trait.stderr b/src/test/ui/consts/const-fn-not-in-trait.stderr
index 12ce3066037..5d364eb882d 100644
--- a/src/test/ui/consts/const-fn-not-in-trait.stderr
+++ b/src/test/ui/consts/const-fn-not-in-trait.stderr
@@ -1,11 +1,11 @@
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/const-fn-not-in-trait.rs:7:5
+  --> $DIR/const-fn-not-in-trait.rs:5:5
    |
 LL |     const fn f() -> u32;
    |     ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/const-fn-not-in-trait.rs:9:5
+  --> $DIR/const-fn-not-in-trait.rs:7:5
    |
 LL |     const fn g() -> u32 {
    |     ^^^^^ functions in traits cannot be const
diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs
index 0446ece421e..726d6e9f74b 100644
--- a/src/test/ui/consts/const-fn-not-safe-for-const.rs
+++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs
@@ -1,6 +1,6 @@
 // Test that we can't call random fns in a const fn or do other bad things.
 
-#![feature(const_fn, const_fn_transmute)]
+#![feature(const_fn_transmute)]
 
 use std::mem::transmute;
 
diff --git a/src/test/ui/consts/const-fn-type-name-any.rs b/src/test/ui/consts/const-fn-type-name-any.rs
index 4ccfb420984..448c4fc0446 100644
--- a/src/test/ui/consts/const-fn-type-name-any.rs
+++ b/src/test/ui/consts/const-fn-type-name-any.rs
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(const_fn)]
 #![feature(const_type_name)]
 #![allow(dead_code)]
 
diff --git a/src/test/ui/consts/const-fn-type-name.rs b/src/test/ui/consts/const-fn-type-name.rs
index 72fac19c191..fd4f60cb889 100644
--- a/src/test/ui/consts/const-fn-type-name.rs
+++ b/src/test/ui/consts/const-fn-type-name.rs
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(core_intrinsics)]
-#![feature(const_fn)]
 #![feature(const_type_name)]
 #![allow(dead_code)]
 
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
index 24df647f05b..03b2f9e3c74 100644
--- a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
+++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
@@ -1,6 +1,5 @@
 // check-pass
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 #![feature(raw_ref_op)]
 
 struct Foo {
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs
index 166ba20f124..f35f3c5e8ef 100644
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs
+++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs
@@ -1,5 +1,4 @@
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 #![feature(raw_ref_op)]
 #![feature(const_raw_ptr_deref)]
 
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
index cbae74cce6f..fb43ce21317 100644
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
+++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
@@ -1,11 +1,11 @@
 error[E0764]: mutable references are not allowed in the final value of constants
-  --> $DIR/mut_ref_in_final.rs:12:21
+  --> $DIR/mut_ref_in_final.rs:11:21
    |
 LL | const B: *mut i32 = &mut 4;
    |                     ^^^^^^
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:18:40
+  --> $DIR/mut_ref_in_final.rs:17:40
    |
 LL | const B3: Option<&mut i32> = Some(&mut 42);
    |                              ----------^^-
@@ -15,7 +15,7 @@ LL | const B3: Option<&mut i32> = Some(&mut 42);
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:21:42
+  --> $DIR/mut_ref_in_final.rs:20:42
    |
 LL | const B4: Option<&mut i32> = helper(&mut 42);
    |                              ------------^^-
@@ -25,7 +25,7 @@ LL | const B4: Option<&mut i32> = helper(&mut 42);
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:36:65
+  --> $DIR/mut_ref_in_final.rs:35:65
    |
 LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                  -------------------------------^^--
@@ -35,7 +35,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                  using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:39:67
+  --> $DIR/mut_ref_in_final.rs:38:67
    |
 LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                    -------------------------------^^--
@@ -45,7 +45,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                    using this value as a static requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:42:71
+  --> $DIR/mut_ref_in_final.rs:41:71
    |
 LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                        -------------------------------^^--
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
index 90977efd2b4..638a98130a2 100644
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
+++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
@@ -1,5 +1,4 @@
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 #![feature(raw_ref_op)]
 #![feature(const_raw_ptr_deref)]
 
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
index 45ae055614b..6d3d18f6e68 100644
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
+++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
@@ -1,12 +1,12 @@
 error: any use of this value will cause an error
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:15:10
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:14:10
    |
 LL |     Some(&mut *(42 as *mut i32))
    |          ^^^^^^^^^^^^^^^^^^^^^^
    |          |
    |          unable to turn bytes into a pointer
-   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:15:10
-   |          inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:20:29
+   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:14:10
+   |          inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:19:29
 ...
 LL | const A: Option<&mut i32> = helper();
    | -------------------------------------
@@ -16,7 +16,7 @@ LL | const A: Option<&mut i32> = helper();
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error: encountered dangling pointer in final constant
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:27:1
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1
    |
 LL | const B: Option<&mut i32> = helper2();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/const_constructor/const-construct-call.rs b/src/test/ui/consts/const_constructor/const-construct-call.rs
index d3e6cf78bc9..cb735d7b305 100644
--- a/src/test/ui/consts/const_constructor/const-construct-call.rs
+++ b/src/test/ui/consts/const_constructor/const-construct-call.rs
@@ -1,11 +1,7 @@
-// Test that constructors are considered to be const fns with the required feature.
+// Test that constructors are considered to be const fns
 
 // run-pass
 
-// revisions: min_const_fn const_fn
-
-#![cfg_attr(const_fn, feature(const_fn))]
-
 // Ctor(..) is transformed to Ctor { 0: ... } in THIR lowering, so directly
 // calling constructors doesn't require them to be const.
 
diff --git a/src/test/ui/consts/const_constructor/const_constructor_qpath.rs b/src/test/ui/consts/const_constructor/const_constructor_qpath.rs
index 18aa3d8e816..7c55f470fdf 100644
--- a/src/test/ui/consts/const_constructor/const_constructor_qpath.rs
+++ b/src/test/ui/consts/const_constructor/const_constructor_qpath.rs
@@ -1,8 +1,5 @@
-// revisions: min_const_fn const_fn
 // run-pass
 
-#![cfg_attr(const_fn, feature(const_fn))]
-
 trait ConstDefault {
     const DEFAULT: Self;
 }
diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs
index 2fd6e060678..1f68de8eed0 100644
--- a/src/test/ui/consts/const_let_assign3.rs
+++ b/src/test/ui/consts/const_let_assign3.rs
@@ -1,5 +1,3 @@
-#![feature(const_fn)]
-
 struct S {
     state: u32,
 }
diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr
index 3eac61c0ce6..89073f975e8 100644
--- a/src/test/ui/consts/const_let_assign3.stderr
+++ b/src/test/ui/consts/const_let_assign3.stderr
@@ -1,5 +1,5 @@
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/const_let_assign3.rs:8:18
+  --> $DIR/const_let_assign3.rs:6:18
    |
 LL |     const fn foo(&mut self, x: u32) {
    |                  ^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     const fn foo(&mut self, x: u32) {
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constants
-  --> $DIR/const_let_assign3.rs:16:5
+  --> $DIR/const_let_assign3.rs:14:5
    |
 LL |     s.foo(3);
    |     ^
@@ -17,7 +17,7 @@ LL |     s.foo(3);
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constants
-  --> $DIR/const_let_assign3.rs:22:13
+  --> $DIR/const_let_assign3.rs:20:13
    |
 LL |     let y = &mut x;
    |             ^^^^^^
diff --git a/src/test/ui/consts/const_unsafe_unreachable.rs b/src/test/ui/consts/const_unsafe_unreachable.rs
index cfed6e5deb9..1fec491ca95 100644
--- a/src/test/ui/consts/const_unsafe_unreachable.rs
+++ b/src/test/ui/consts/const_unsafe_unreachable.rs
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(const_fn)]
 #![feature(const_unreachable_unchecked)]
 
 const unsafe fn foo(x: bool) -> bool {
diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs
index 0bd37876cc3..4ae3a88c451 100644
--- a/src/test/ui/consts/const_unsafe_unreachable_ub.rs
+++ b/src/test/ui/consts/const_unsafe_unreachable_ub.rs
@@ -1,6 +1,5 @@
 // build-fail
 
-#![feature(const_fn)]
 #![feature(const_unreachable_unchecked)]
 
 const unsafe fn foo(x: bool) -> bool {
diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
index 3f122b2a859..68d8747d287 100644
--- a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
+++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
@@ -6,16 +6,16 @@ LL |     unsafe { intrinsics::unreachable() }
    |              |
    |              entering unreachable code
    |              inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL
-   |              inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18
-   |              inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28
+   |              inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:8:18
+   |              inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:13:28
    | 
-  ::: $DIR/const_unsafe_unreachable_ub.rs:14:1
+  ::: $DIR/const_unsafe_unreachable_ub.rs:13:1
    |
 LL | const BAR: bool = unsafe { foo(false) };
    | ----------------------------------------
    |
 note: the lint level is defined here
-  --> $DIR/const_unsafe_unreachable_ub.rs:13:8
+  --> $DIR/const_unsafe_unreachable_ub.rs:12:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
@@ -23,13 +23,13 @@ LL | #[warn(const_err)]
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_unsafe_unreachable_ub.rs:17:14
+  --> $DIR/const_unsafe_unreachable_ub.rs:16:14
    |
 LL |   assert_eq!(BAR, true);
    |              ^^^ referenced constant has errors
 
 error: erroneous constant used
-  --> $DIR/const_unsafe_unreachable_ub.rs:17:3
+  --> $DIR/const_unsafe_unreachable_ub.rs:16:3
    |
 LL |   assert_eq!(BAR, true);
    |   ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs
index 6dd6192941d..3a4f24bbcc3 100644
--- a/src/test/ui/consts/control-flow/basics.rs
+++ b/src/test/ui/consts/control-flow/basics.rs
@@ -3,7 +3,6 @@
 // run-pass
 
 #![feature(const_panic)]
-#![feature(const_fn)]
 
 const X: u32 = 4;
 const Y: u32 = 5;
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index 292e2dd167c..35aa587d3d2 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)]
+#![feature(const_fn_floating_point_arithmetic, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 0f48341ddf3..962a57bb8e9 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)]
+#![feature(const_fn_floating_point_arithmetic, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -25,7 +25,7 @@ const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
-// conformity is required, even with `const_fn` feature gate
+// conformity is required
 const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
 //~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]`
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index d17dcb28115..194f5fc1e54 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn, foo, foo2)]
+#![feature(foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs
index 0d0c78b0fc2..20c1169c26e 100644
--- a/src/test/ui/consts/promote-not.rs
+++ b/src/test/ui/consts/promote-not.rs
@@ -1,7 +1,7 @@
 // ignore-tidy-linelength
 // Test various things that we do not want to promote.
 #![allow(unconditional_panic, const_err)]
-#![feature(const_fn, const_fn_union)]
+#![feature(const_fn_union)]
 
 use std::cell::Cell;
 
diff --git a/src/test/ui/consts/rustc-args-required-const.rs b/src/test/ui/consts/rustc-args-required-const.rs
index 87f979f1b27..0723b66879c 100644
--- a/src/test/ui/consts/rustc-args-required-const.rs
+++ b/src/test/ui/consts/rustc-args-required-const.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_attrs, const_fn)]
+#![feature(rustc_attrs)]
 
 #[rustc_args_required_const(0)]
 fn foo(_a: i32) {
diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
index 651462d7ef1..2b970390f03 100644
--- a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
+++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
@@ -1,6 +1,6 @@
 #![stable(feature = "core", since = "1.6.0")]
 #![feature(staged_api)]
-#![feature(const_precise_live_drops, const_fn)]
+#![feature(const_precise_live_drops)]
 
 enum Either<T, S> {
     Left(T),
diff --git a/src/test/ui/entry-point/auxiliary/main_functions.rs b/src/test/ui/entry-point/auxiliary/main_functions.rs
new file mode 100644
index 00000000000..cc7992a42c1
--- /dev/null
+++ b/src/test/ui/entry-point/auxiliary/main_functions.rs
@@ -0,0 +1 @@
+pub fn boilerplate() {}
diff --git a/src/test/ui/entry-point/imported_main_conflict.rs b/src/test/ui/entry-point/imported_main_conflict.rs
new file mode 100644
index 00000000000..2839688f342
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_conflict.rs
@@ -0,0 +1,7 @@
+#![feature(imported_main)]
+//~^ ERROR `main` is ambiguous (glob import vs glob import in the same module)
+mod m1 { pub(crate) fn main() {} }
+mod m2 { pub(crate) fn main() {} }
+
+use m1::*;
+use m2::*;
diff --git a/src/test/ui/entry-point/imported_main_conflict.stderr b/src/test/ui/entry-point/imported_main_conflict.stderr
new file mode 100644
index 00000000000..36cb98d94e6
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_conflict.stderr
@@ -0,0 +1,18 @@
+error[E0659]: `main` is ambiguous (glob import vs glob import in the same module)
+   |
+note: `main` could refer to the function imported here
+  --> $DIR/imported_main_conflict.rs:6:5
+   |
+LL | use m1::*;
+   |     ^^^^^
+   = help: consider adding an explicit import of `main` to disambiguate
+note: `main` could also refer to the function imported here
+  --> $DIR/imported_main_conflict.rs:7:5
+   |
+LL | use m2::*;
+   |     ^^^^^
+   = help: consider adding an explicit import of `main` to disambiguate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs
new file mode 100644
index 00000000000..559f10de109
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs
@@ -0,0 +1,12 @@
+#![feature(imported_main)]
+#![feature(min_type_alias_impl_trait, impl_trait_in_bindings)]
+#![allow(incomplete_features)]
+//~^^^ ERROR `main` function not found in crate
+pub mod foo {
+    type MainFn = impl Fn();
+
+    fn bar() {}
+    pub const BAR: MainFn = bar;
+}
+
+use foo::BAR as main;
diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
new file mode 100644
index 00000000000..9b879fc09f7
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
@@ -0,0 +1,17 @@
+error[E0601]: `main` function not found in crate `imported_main_const_fn_item_type_forbidden`
+  --> $DIR/imported_main_const_fn_item_type_forbidden.rs:1:1
+   |
+LL | / #![feature(imported_main)]
+LL | | #![feature(min_type_alias_impl_trait, impl_trait_in_bindings)]
+LL | | #![allow(incomplete_features)]
+LL | |
+...  |
+LL | |
+LL | | use foo::BAR as main;
+   | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs`
+   |       |
+   |       non-function item at `crate::main` is found
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.rs b/src/test/ui/entry-point/imported_main_const_forbidden.rs
new file mode 100644
index 00000000000..989a6c97a80
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_const_forbidden.rs
@@ -0,0 +1,7 @@
+#![feature(imported_main)]
+//~^ ERROR `main` function not found in crate
+pub mod foo {
+    pub const BAR: usize = 42;
+}
+
+use foo::BAR as main;
diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_forbidden.stderr
new file mode 100644
index 00000000000..4640513c2bb
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_const_forbidden.stderr
@@ -0,0 +1,17 @@
+error[E0601]: `main` function not found in crate `imported_main_const_forbidden`
+  --> $DIR/imported_main_const_forbidden.rs:1:1
+   |
+LL | / #![feature(imported_main)]
+LL | |
+LL | | pub mod foo {
+LL | |     pub const BAR: usize = 42;
+LL | | }
+LL | |
+LL | | use foo::BAR as main;
+   | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_forbidden.rs`
+   |       |
+   |       non-function item at `crate::main` is found
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.rs b/src/test/ui/entry-point/imported_main_from_extern_crate.rs
new file mode 100644
index 00000000000..6bbf67fa540
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_from_extern_crate.rs
@@ -0,0 +1,9 @@
+// build-fail
+// aux-build:main_functions.rs
+
+#![feature(imported_main)]
+
+extern crate main_functions;
+pub use main_functions::boilerplate as main; //~ ERROR entry symbol `main` from foreign crate
+
+// FIXME: Should be run-pass
diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.stderr b/src/test/ui/entry-point/imported_main_from_extern_crate.stderr
new file mode 100644
index 00000000000..8792e1e4142
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_from_extern_crate.stderr
@@ -0,0 +1,10 @@
+error: entry symbol `main` from foreign crate is not yet supported.
+  --> $DIR/imported_main_from_extern_crate.rs:7:9
+   |
+LL | pub use main_functions::boilerplate as main;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #28937 <https://github.com/rust-lang/rust/issues/28937> for more information
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/entry-point/imported_main_from_inner_mod.rs b/src/test/ui/entry-point/imported_main_from_inner_mod.rs
new file mode 100644
index 00000000000..45750072a7f
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_from_inner_mod.rs
@@ -0,0 +1,9 @@
+// run-pass
+#![feature(imported_main)]
+
+pub mod foo {
+    pub fn bar() {
+        println!("Hello world!");
+    }
+}
+use foo::bar as main;
diff --git a/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs b/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs
new file mode 100644
index 00000000000..4762fbb7c59
--- /dev/null
+++ b/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs
@@ -0,0 +1,11 @@
+// check-pass
+#![feature(rustc_attrs)]
+
+#[rustc_main]
+fn actual_main() {}
+
+mod foo {
+    pub(crate) fn something() {}
+}
+
+use foo::something as main;
diff --git a/src/test/ui/error-codes/E0504.stderr b/src/test/ui/error-codes/E0504.stderr
index 1f2a0407a39..04811721aa5 100644
--- a/src/test/ui/error-codes/E0504.stderr
+++ b/src/test/ui/error-codes/E0504.stderr
@@ -7,7 +7,7 @@ LL |
 LL |     let x = move || {
    |             ^^^^^^^ move out of `fancy_num` occurs here
 LL |         println!("child function: {}", fancy_num.num);
-   |                                        --------- move occurs due to use in closure
+   |                                        ------------- move occurs due to use in closure
 ...
 LL |     println!("main function: {}", fancy_ref.num);
    |                                   ------------- borrow later used here
diff --git a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs
deleted file mode 100644
index 430a9437cee..00000000000
--- a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// Feature gate test for `edition_macro_pats` feature.
-
-macro_rules! foo {
-    ($x:pat2015) => {}; //~ERROR `pat2015` and `pat2021` are unstable
-    ($x:pat2021) => {}; //~ERROR `pat2015` and `pat2021` are unstable
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr
deleted file mode 100644
index d25bcaf929b..00000000000
--- a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `pat2015` and `pat2021` are unstable.
-  --> $DIR/feature-gate-edition_macro_pats.rs:4:9
-   |
-LL |     ($x:pat2015) => {};
-   |         ^^^^^^^
-   |
-   = note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
-   = help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable
-
-error[E0658]: `pat2015` and `pat2021` are unstable.
-  --> $DIR/feature-gate-edition_macro_pats.rs:5:9
-   |
-LL |     ($x:pat2021) => {};
-   |         ^^^^^^^
-   |
-   = note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
-   = help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.rs b/src/test/ui/feature-gates/feature-gate-imported_main.rs
new file mode 100644
index 00000000000..b351d0d0e9a
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-imported_main.rs
@@ -0,0 +1,6 @@
+pub mod foo {
+    pub fn bar() {
+        println!("Hello world!");
+    }
+}
+use foo::bar as main; //~ ERROR using an imported function as entry point
diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.stderr b/src/test/ui/feature-gates/feature-gate-imported_main.stderr
new file mode 100644
index 00000000000..3b879fdfc6b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-imported_main.stderr
@@ -0,0 +1,12 @@
+error[E0658]: using an imported function as entry point `main` is experimental
+  --> $DIR/feature-gate-imported_main.rs:6:5
+   |
+LL | use foo::bar as main;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #28937 <https://github.com/rust-lang/rust/issues/28937> for more information
+   = help: add `#![feature(imported_main)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-no_coverage.rs b/src/test/ui/feature-gates/feature-gate-no_coverage.rs
new file mode 100644
index 00000000000..c6b79f9a431
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-no_coverage.rs
@@ -0,0 +1,8 @@
+#![crate_type = "lib"]
+
+#[no_coverage]
+#[feature(no_coverage)] // does not have to be enabled before `#[no_coverage]`
+fn no_coverage_is_enabled_on_this_function() {}
+
+#[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature
+fn requires_feature_no_coverage() {}
diff --git a/src/test/ui/feature-gates/feature-gate-no_coverage.stderr b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr
new file mode 100644
index 00000000000..04627be4aaf
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr
@@ -0,0 +1,13 @@
+error[E0658]: the `#[no_coverage]` attribute is an experimental feature
+  --> $DIR/feature-gate-no_coverage.rs:7:1
+   |
+LL | #[no_coverage]
+   | ^^^^^^^^^^^^^^
+   |
+   = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
+   = help: add `#![feature(no_coverage)]` to the crate attributes to enable
+   = help: or, alternatively, add `#[feature(no_coverage)]` to the function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr
index fd885660d09..68d785efcfe 100644
--- a/src/test/ui/generator/yield-while-ref-reborrowed.stderr
+++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr
@@ -4,7 +4,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
 LL |     let mut b = || {
    |                 -- generator construction occurs here
 LL |         let a = &mut *x;
-   |                       - first borrow occurs due to use of `x` in generator
+   |                      -- first borrow occurs due to use of `x` in generator
 ...
 LL |     println!("{}", x);
    |                    ^ second borrow occurs here
diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.rs b/src/test/ui/generic-associated-types/gat-in-trait-path.rs
index 2dbd1840dec..6527eb47504 100644
--- a/src/test/ui/generic-associated-types/gat-in-trait-path.rs
+++ b/src/test/ui/generic-associated-types/gat-in-trait-path.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(generic_associated_types)]
   //~^ WARNING: the feature `generic_associated_types` is incomplete
 #![feature(associated_type_defaults)]
@@ -22,6 +20,7 @@ impl<T> Foo for Fooer<T> {
 }
 
 fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
+//~^ the trait `Foo` cannot be made into an object
 
 
 fn main() {
diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr
index f3769827f04..49dfce8b4bd 100644
--- a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr
+++ b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr
@@ -1,5 +1,5 @@
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/gat-in-trait-path.rs:3:12
+  --> $DIR/gat-in-trait-path.rs:1:12
    |
 LL | #![feature(generic_associated_types)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,5 +7,21 @@ 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
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/gat-in-trait-path.rs:22:13
+   |
+LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+   = help: consider moving `A` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/gat-in-trait-path.rs:6:10
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     type A<'a> where Self: 'a;
+   |          ^ ...because it contains the generic associated type `A`
+
+error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.rs b/src/test/ui/generic-associated-types/issue-67510-pass.rs
index ff38b3e93eb..6ee865072ae 100644
--- a/src/test/ui/generic-associated-types/issue-67510-pass.rs
+++ b/src/test/ui/generic-associated-types/issue-67510-pass.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(generic_associated_types)]
   //~^ WARNING: the feature `generic_associated_types` is incomplete
 
@@ -8,5 +6,6 @@ trait X {
 }
 
 fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
+//~^ ERROR the trait `X` cannot be made into an object
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr
index 0fbf704df76..65998afa7f9 100644
--- a/src/test/ui/generic-associated-types/issue-67510-pass.stderr
+++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr
@@ -1,5 +1,5 @@
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-67510-pass.rs:3:12
+  --> $DIR/issue-67510-pass.rs:1:12
    |
 LL | #![feature(generic_associated_types)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,5 +7,21 @@ 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
+error[E0038]: the trait `X` cannot be made into an object
+  --> $DIR/issue-67510-pass.rs:8:19
+   |
+LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |
+   = help: consider moving `Y` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-67510-pass.rs:5:10
+   |
+LL | trait X {
+   |       - this trait cannot be made into an object...
+LL |     type Y<'a>;
+   |          ^ ...because it contains the generic associated type `Y`
+
+error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs
index 5e73a882986..9643c82db77 100644
--- a/src/test/ui/generic-associated-types/issue-76535.rs
+++ b/src/test/ui/generic-associated-types/issue-76535.rs
@@ -36,4 +36,6 @@ impl SuperTrait for SuperStruct {
 
 fn main() {
     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
+    //~^ ERROR the trait `SuperTrait` cannot be made into an object
+    //~^^ ERROR the trait `SuperTrait` cannot be made into an object
 }
diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr
index 17661e0d90a..d31560f12f0 100644
--- a/src/test/ui/generic-associated-types/issue-76535.stderr
+++ b/src/test/ui/generic-associated-types/issue-76535.stderr
@@ -23,6 +23,39 @@ help: use angle brackets to add missing lifetime argument
 LL |     type SubType<'a><'a>: SubTrait;
    |                 ^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error[E0038]: the trait `SuperTrait` cannot be made into an object
+  --> $DIR/issue-76535.rs:38:14
+   |
+LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |
+   = help: consider moving `SubType` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-76535.rs:7:10
+   |
+LL | pub trait SuperTrait {
+   |           ---------- this trait cannot be made into an object...
+LL |     type SubType<'a>: SubTrait;
+   |          ^^^^^^^ ...because it contains the generic associated type `SubType`
+
+error[E0038]: the trait `SuperTrait` cannot be made into an object
+  --> $DIR/issue-76535.rs:38:57
+   |
+LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |
+   = help: consider moving `SubType` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-76535.rs:7:10
+   |
+LL | pub trait SuperTrait {
+   |           ---------- this trait cannot be made into an object...
+LL |     type SubType<'a>: SubTrait;
+   |          ^^^^^^^ ...because it contains the generic associated type `SubType`
+   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
+   = note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-78671.rs b/src/test/ui/generic-associated-types/issue-78671.rs
index 1b02aac8bcb..4e47d3c6655 100644
--- a/src/test/ui/generic-associated-types/issue-78671.rs
+++ b/src/test/ui/generic-associated-types/issue-78671.rs
@@ -7,6 +7,7 @@ trait CollectionFamily {
 }
 fn floatify() {
     Box::new(Family) as &dyn CollectionFamily<Member=usize>
+    //~^ the trait `CollectionFamily` cannot be made into an object
 }
 
 struct Family;
diff --git a/src/test/ui/generic-associated-types/issue-78671.stderr b/src/test/ui/generic-associated-types/issue-78671.stderr
index 7a9aced5bea..c9febfb59af 100644
--- a/src/test/ui/generic-associated-types/issue-78671.stderr
+++ b/src/test/ui/generic-associated-types/issue-78671.stderr
@@ -14,6 +14,22 @@ help: use angle brackets to add missing type argument
 LL |     type Member<T><T>;
    |                ^^^
 
-error: aborting due to previous error
+error[E0038]: the trait `CollectionFamily` cannot be made into an object
+  --> $DIR/issue-78671.rs:9:25
+   |
+LL |     Box::new(Family) as &dyn CollectionFamily<Member=usize>
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object
+   |
+   = help: consider moving `Member` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-78671.rs:5:10
+   |
+LL | trait CollectionFamily {
+   |       ---------------- this trait cannot be made into an object...
+LL |     type Member<T>;
+   |          ^^^^^^ ...because it contains the generic associated type `Member`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs
index aeb33ca5464..b2ba3c24abb 100644
--- a/src/test/ui/generic-associated-types/issue-79422.rs
+++ b/src/test/ui/generic-associated-types/issue-79422.rs
@@ -42,5 +42,6 @@ impl<K, V: Default> MapLike<K, V> for Source {
 fn main() {
     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-    //~^^ ERROR type mismatch resolving
+    //~^^ the trait `MapLike` cannot be made into an object
+    //~^^ the trait `MapLike` cannot be made into an object
 }
diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr
index a119bff03e2..4973ae19729 100644
--- a/src/test/ui/generic-associated-types/issue-79422.stderr
+++ b/src/test/ui/generic-associated-types/issue-79422.stderr
@@ -14,17 +14,39 @@ help: use angle brackets to add missing lifetime argument
 LL |     type VRefCont<'a><'a>: RefCont<'a, V>;
    |                  ^^^^
 
-error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)`
+error[E0038]: the trait `MapLike` cannot be made into an object
+  --> $DIR/issue-79422.rs:44:12
+   |
+LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |
+   = help: consider moving `VRefCont` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-79422.rs:21:10
+   |
+LL | trait MapLike<K, V> {
+   |       ------- this trait cannot be made into an object...
+LL |     type VRefCont<'a>: RefCont<'a, V>;
+   |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
+
+error[E0038]: the trait `MapLike` cannot be made into an object
   --> $DIR/issue-79422.rs:43:13
    |
 LL |     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |
+   = help: consider moving `VRefCont` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-79422.rs:21:10
    |
-   = note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
-                 found reference `&'static u8`
-   = note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>`
+LL | trait MapLike<K, V> {
+   |       ------- this trait cannot be made into an object...
+LL |     type VRefCont<'a>: RefCont<'a, V>;
+   |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
+   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
+   = note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0107, E0271.
-For more information about an error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/trait-objects.rs b/src/test/ui/generic-associated-types/trait-objects.rs
new file mode 100644
index 00000000000..997a550b0ef
--- /dev/null
+++ b/src/test/ui/generic-associated-types/trait-objects.rs
@@ -0,0 +1,16 @@
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait StreamingIterator {
+    type Item<'a> where Self: 'a;
+    fn size_hint(&self) -> (usize, Option<usize>);
+    // Uncommenting makes `StreamingIterator` not object safe
+//    fn next(&mut self) -> Self::Item<'_>;
+}
+
+fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
+    //~^ the trait `StreamingIterator` cannot be made into an object
+    x.size_hint().0
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/trait-objects.stderr b/src/test/ui/generic-associated-types/trait-objects.stderr
new file mode 100644
index 00000000000..a8f1768ba26
--- /dev/null
+++ b/src/test/ui/generic-associated-types/trait-objects.stderr
@@ -0,0 +1,18 @@
+error[E0038]: the trait `StreamingIterator` cannot be made into an object
+  --> $DIR/trait-objects.rs:11:16
+   |
+LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |
+   = help: consider moving `Item` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/trait-objects.rs:5:10
+   |
+LL | trait StreamingIterator {
+   |       ----------------- this trait cannot be made into an object...
+LL |     type Item<'a> where Self: 'a;
+   |          ^^^^ ...because it contains the generic associated type `Item`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/issues/issue-11192.stderr b/src/test/ui/issues/issue-11192.stderr
index dfe7b3f6b5f..2a9d913171c 100644
--- a/src/test/ui/issues/issue-11192.stderr
+++ b/src/test/ui/issues/issue-11192.stderr
@@ -5,7 +5,7 @@ LL |     let mut test = |foo: &Foo| {
    |                    ----------- mutable borrow occurs here
 LL |         println!("access {}", foo.x);
 LL |         ptr = box Foo { x: ptr.x + 1 };
-   |                            --- first borrow occurs due to use of `ptr` in closure
+   |         --- first borrow occurs due to use of `ptr` in closure
 ...
 LL |     test(&*ptr);
    |     ---- ^^^^^ immutable borrow occurs here
diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr
index 188f0b25c30..a1f973e0fdf 100644
--- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr
+++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr
@@ -5,7 +5,7 @@ LL |     match x {
    |           - value is immutable in match guard
 ...
 LL |             (|| { *x = None; drop(force_fn_once); })();
-   |              ^^    - borrow occurs due to use of `x` in closure
+   |              ^^   -- borrow occurs due to use of `x` in closure
    |              |
    |              cannot mutably borrow
 
diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr
index f46a42d7508..4a4a25790b9 100644
--- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr
+++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr
@@ -5,7 +5,7 @@ LL |     match **x {
    |           --- value is immutable in match guard
 ...
 LL |             (|| { *x = &None; drop(force_fn_once); })();
-   |              ^^    - borrow occurs due to use of `x` in closure
+   |              ^^   -- borrow occurs due to use of `x` in closure
    |              |
    |              cannot mutably borrow
 
diff --git a/src/test/ui/issues/issue-61623.stderr b/src/test/ui/issues/issue-61623.stderr
index 883a1c441d6..901c7598176 100644
--- a/src/test/ui/issues/issue-61623.stderr
+++ b/src/test/ui/issues/issue-61623.stderr
@@ -10,7 +10,7 @@ error[E0502]: cannot borrow `*x.1` as mutable because it is also borrowed as imm
   --> $DIR/issue-61623.rs:6:19
    |
 LL |     f2(|| x.0, f1(x.1))
-   |     -- -- -       ^^^ mutable borrow occurs here
+   |     -- -- ---     ^^^ mutable borrow occurs here
    |     |  |  |
    |     |  |  first borrow occurs due to use of `x` in closure
    |     |  immutable borrow occurs here
diff --git a/src/test/ui/issues/issue-6801.stderr b/src/test/ui/issues/issue-6801.stderr
index dbb8e6530c0..48c6acd1f49 100644
--- a/src/test/ui/issues/issue-6801.stderr
+++ b/src/test/ui/issues/issue-6801.stderr
@@ -2,7 +2,7 @@ error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/issue-6801.rs:19:13
    |
 LL |       let sq =  || { *x * *x };
-   |                 --    - borrow occurs due to use in closure
+   |                 --   -- borrow occurs due to use in closure
    |                 |
    |                 borrow of `x` occurs here
 LL | 
diff --git a/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs b/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs
new file mode 100644
index 00000000000..c496a3556c8
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs
@@ -0,0 +1,14 @@
+// build-pass
+// compile-flags: --edition 2018
+// compile-flags: --crate-type rlib
+
+use std::future::Future;
+
+async fn handle<F>(slf: &F)
+where
+    F: Fn(&()) -> Box<dyn for<'a> Future<Output = ()> + Unpin>,
+{
+    (slf)(&()).await;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-84604.rs b/src/test/ui/lifetimes/issue-84604.rs
new file mode 100644
index 00000000000..df8368da0a0
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-84604.rs
@@ -0,0 +1,9 @@
+// run-pass
+// compile-flags: -Zsymbol-mangling-version=v0
+
+pub fn f<T: ?Sized>() {}
+pub trait Frob<T: ?Sized> {}
+fn main() {
+    f::<dyn Frob<str>>();
+    f::<dyn for<'a> Frob<str>>();
+}
diff --git a/src/test/ui/macros/edition-macro-pats.rs b/src/test/ui/macros/edition-macro-pats.rs
index 58f92710305..040894712a8 100644
--- a/src/test/ui/macros/edition-macro-pats.rs
+++ b/src/test/ui/macros/edition-macro-pats.rs
@@ -1,10 +1,9 @@
 // run-pass
-
-#![feature(edition_macro_pats)]
+// edition:2021
 
 macro_rules! foo {
-    (a $x:pat2015) => {};
-    (b $x:pat2021) => {};
+    (a $x:pat_param) => {};
+    (b $x:pat) => {};
 }
 
 fn main() {
diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.fixed b/src/test/ui/macros/macro-or-patterns-back-compat.fixed
index f089f0fda4e..f829129d516 100644
--- a/src/test/ui/macros/macro-or-patterns-back-compat.fixed
+++ b/src/test/ui/macros/macro-or-patterns-back-compat.fixed
@@ -1,15 +1,14 @@
 // run-rustfix
 
-#![feature(edition_macro_pats)]
 #![deny(or_patterns_back_compat)]
 #![allow(unused_macros)]
-macro_rules! foo { ($x:pat2015 | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-macro_rules! bar { ($($x:pat2015)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok
-macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok
-macro_rules! ogg { ($x:pat2015 | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+macro_rules! foo { ($x:pat_param | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+macro_rules! bar { ($($x:pat_param)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
+macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
+macro_rules! ogg { ($x:pat_param | $y:pat_param) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
 macro_rules! match_any {
-    ( $expr:expr , $( $( $pat:pat2015 )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+    ( $expr:expr , $( $( $pat:pat_param )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
         match $expr {
             $(
                 $( $pat => $expr_arm, )+
diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.rs b/src/test/ui/macros/macro-or-patterns-back-compat.rs
index 0252581d5f1..1cdaa1cd631 100644
--- a/src/test/ui/macros/macro-or-patterns-back-compat.rs
+++ b/src/test/ui/macros/macro-or-patterns-back-compat.rs
@@ -1,13 +1,12 @@
 // run-rustfix
 
-#![feature(edition_macro_pats)]
 #![deny(or_patterns_back_compat)]
 #![allow(unused_macros)]
 macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
 macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok
-macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok
-macro_rules! ogg { ($x:pat | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
+macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
+macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
 macro_rules! match_any {
     ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
         match $expr {
diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.stderr b/src/test/ui/macros/macro-or-patterns-back-compat.stderr
index d8f19fa5807..01d220dd0b1 100644
--- a/src/test/ui/macros/macro-or-patterns-back-compat.stderr
+++ b/src/test/ui/macros/macro-or-patterns-back-compat.stderr
@@ -1,32 +1,32 @@
 error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-  --> $DIR/macro-or-patterns-back-compat.rs:6:21
+  --> $DIR/macro-or-patterns-back-compat.rs:5:21
    |
 LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
-   |                     ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015`
+   |                     ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
    |
 note: the lint level is defined here
-  --> $DIR/macro-or-patterns-back-compat.rs:4:9
+  --> $DIR/macro-or-patterns-back-compat.rs:3:9
    |
 LL | #![deny(or_patterns_back_compat)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-  --> $DIR/macro-or-patterns-back-compat.rs:7:23
+  --> $DIR/macro-or-patterns-back-compat.rs:6:23
    |
 LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
-   |                       ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015`
+   |                       ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
 
 error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-  --> $DIR/macro-or-patterns-back-compat.rs:10:21
+  --> $DIR/macro-or-patterns-back-compat.rs:9:21
    |
-LL | macro_rules! ogg { ($x:pat | $y:pat2015) => {} }
-   |                     ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015`
+LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
+   |                     ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
 
 error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-  --> $DIR/macro-or-patterns-back-compat.rs:12:26
+  --> $DIR/macro-or-patterns-back-compat.rs:11:26
    |
 LL |     ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
-   |                          ^^^^^^^^ help: use pat2015 to preserve semantics: `$pat:pat2015`
+   |                          ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs
index edd3f3e7646..b4be03aaddd 100644
--- a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs
+++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs
@@ -1,11 +1,12 @@
-#![feature(edition_macro_pats)]
+// edition:2021
+
 #![allow(unused_macros)]
-macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
-macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok
-macro_rules! qux { ($x:pat2015 | $y:pat2021) => {} } // should be ok
-macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
+macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
+macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
+macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
 macro_rules! match_any {
-    ( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => { //~ ERROR  `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments
+    ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { //~ ERROR  `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
         match $expr {
             $(
                 $( $pat => $expr_arm, )+
diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
index fe0b40cd86e..8aebe98515f 100644
--- a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
+++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
@@ -1,24 +1,24 @@
-error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
-  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:3:32
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28
    |
-LL | macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} }
-   |                                ^ not allowed after `pat2021` fragments
+LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
+   |                            ^ not allowed after `pat` fragments
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
-error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments
-  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:6:32
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28
    |
-LL | macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} }
-   |                                ^ not allowed after `pat2021` fragments
+LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
+   |                            ^ not allowed after `pat` fragments
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
-error: `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments
-  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:8:40
+error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35
    |
-LL |     ( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => {
-   |                                        ^ not allowed after `pat2021` fragments
+LL |     ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => {
+   |                                   ^ not allowed after `pat` fragments
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr
index ccc043a1890..8eded8f2857 100644
--- a/src/test/ui/nll/closure-access-spans.stderr
+++ b/src/test/ui/nll/closure-access-spans.stderr
@@ -28,7 +28,7 @@ error[E0500]: closure requires unique access to `x` but it is already borrowed
 LL |     let r = &mut x;
    |             ------ borrow occurs here
 LL |     || *x = 2;
-   |     ^^  - second borrow occurs due to use of `x` in closure
+   |     ^^ -- second borrow occurs due to use of `x` in closure
    |     |
    |     closure construction occurs here
 LL |     r.use_mut();
@@ -88,7 +88,7 @@ LL | fn closure_unique_capture_moved(x: &mut String) {
 LL |     let r = x;
    |             - value moved here
 LL |     || *x = String::new();
-   |     ^^  - borrow occurs due to use in closure
+   |     ^^ -- borrow occurs due to use in closure
    |     |
    |     value borrowed here after move
 
diff --git a/src/test/ui/nll/closure-borrow-spans.stderr b/src/test/ui/nll/closure-borrow-spans.stderr
index a3bcbbab3ec..fffbee4d4a8 100644
--- a/src/test/ui/nll/closure-borrow-spans.stderr
+++ b/src/test/ui/nll/closure-borrow-spans.stderr
@@ -110,7 +110,7 @@ error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/closure-borrow-spans.rs:65:13
    |
 LL |     let f = || *x = 0;
-   |             --  - borrow occurs due to use in closure
+   |             -- -- borrow occurs due to use in closure
    |             |
    |             borrow of `x` occurs here
 LL |     let y = x;
@@ -122,7 +122,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
   --> $DIR/closure-borrow-spans.rs:71:13
    |
 LL |     let f = || *x = 0;
-   |             --  - first borrow occurs due to use of `x` in closure
+   |             -- -- first borrow occurs due to use of `x` in closure
    |             |
    |             closure construction occurs here
 LL |     let y = &x;
@@ -134,7 +134,7 @@ error[E0501]: cannot borrow `x` as mutable because previous closure requires uni
   --> $DIR/closure-borrow-spans.rs:77:13
    |
 LL |     let f = || *x = 0;
-   |             --  - first borrow occurs due to use of `x` in closure
+   |             -- -- first borrow occurs due to use of `x` in closure
    |             |
    |             closure construction occurs here
 LL |     let y = &mut x;
@@ -143,10 +143,10 @@ LL |     f.use_ref();
    |     - first borrow later used here
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/closure-borrow-spans.rs:86:17
+  --> $DIR/closure-borrow-spans.rs:86:16
    |
 LL |         f = || *x = 0;
-   |             --  ^ borrowed value does not live long enough
+   |             -- ^^ borrowed value does not live long enough
    |             |
    |             value captured here
 LL |     }
@@ -158,7 +158,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/closure-borrow-spans.rs:93:5
    |
 LL |     let f = || *x = 0;
-   |             --  - borrow occurs due to use in closure
+   |             -- -- borrow occurs due to use in closure
    |             |
    |             borrow of `*x` occurs here
 LL |     *x = 1;
diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr
index dd5f32ef4f5..a59e553315a 100644
--- a/src/test/ui/nll/closure-captures.stderr
+++ b/src/test/ui/nll/closure-captures.stderr
@@ -133,9 +133,9 @@ LL |       fn_ref(|| {
 LL | |         ||
    | |         ^^ cannot borrow as mutable
 LL | |         *x = 1;});
-   | |__________-_____- in this closure
-   |            |
-   |            mutable borrow occurs due to use of `x` in closure
+   | |_________--_____- in this closure
+   |           |
+   |           mutable borrow occurs due to use of `x` in closure
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:51:9
@@ -150,9 +150,9 @@ LL |       fn_ref(move || {
 LL | |         ||
    | |         ^^ cannot borrow as mutable
 LL | |         *x = 1;});
-   | |__________-_____- in this closure
-   |            |
-   |            mutable borrow occurs due to use of `x` in closure
+   | |_________--_____- in this closure
+   |           |
+   |           mutable borrow occurs due to use of `x` in closure
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/nll/closure-use-spans.stderr b/src/test/ui/nll/closure-use-spans.stderr
index ec7e0f30855..87162904ba6 100644
--- a/src/test/ui/nll/closure-use-spans.stderr
+++ b/src/test/ui/nll/closure-use-spans.stderr
@@ -6,7 +6,7 @@ LL |     let y = &x;
 LL |     x = 0;
    |     ^^^^^ assignment to borrowed `x` occurs here
 LL |     || *y;
-   |         - borrow later captured here by closure
+   |        -- borrow later captured here by closure
 
 error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/closure-use-spans.rs:11:5
@@ -16,7 +16,7 @@ LL |     let y = &mut x;
 LL |     x = 0;
    |     ^^^^^ assignment to borrowed `x` occurs here
 LL |     || *y = 1;
-   |         - borrow later captured here by closure
+   |        -- borrow later captured here by closure
 
 error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/closure-use-spans.rs:17:5
diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr
index 2f134f83ced..2be0460df1f 100644
--- a/src/test/ui/nll/closures-in-loops.stderr
+++ b/src/test/ui/nll/closures-in-loops.stderr
@@ -21,7 +21,7 @@ error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/closures-in-loops.rs:20:16
    |
 LL |         v.push(|| *x = String::new());
-   |                ^^  - borrows occur due to use of `x` in closure
+   |                ^^ -- borrows occur due to use of `x` in closure
    |                |
    |                closures are constructed here in different iterations of loop
 
diff --git a/src/test/ui/nll/issue-51268.stderr b/src/test/ui/nll/issue-51268.stderr
index e6dadc9f6ce..0483bda6379 100644
--- a/src/test/ui/nll/issue-51268.stderr
+++ b/src/test/ui/nll/issue-51268.stderr
@@ -8,7 +8,7 @@ LL |           self.thing.bar(|| {
    | |
 LL | |
 LL | |             &self.number;
-   | |              ---- first borrow occurs due to use of `self` in closure
+   | |              ----------- first borrow occurs due to use of `self` in closure
 LL | |         });
    | |__________^ mutable borrow occurs here
 
diff --git a/src/test/ui/or-patterns/macro-pat.rs b/src/test/ui/or-patterns/macro-pat.rs
index 8c581b630de..20d8f84c247 100644
--- a/src/test/ui/or-patterns/macro-pat.rs
+++ b/src/test/ui/or-patterns/macro-pat.rs
@@ -1,10 +1,9 @@
 // run-pass
 // edition:2021
-// ignore-test
-// FIXME(mark-i-m): enable this test again when 2021 machinery is available
 
 use Foo::*;
 
+#[allow(dead_code)]
 #[derive(Eq, PartialEq, Debug)]
 enum Foo {
     A(u64),
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs
index f0ce7597aee..c0d148d9204 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs
@@ -1,9 +1,7 @@
 // Tests that :pat in macros in edition 2021 allows top-level or-patterns.
 
 // run-pass
-// ignore-test
 // edition:2021
-// FIXME(mark-i-m): unignore when 2021 machinery is in place.
 
 macro_rules! accept_pat {
     ($p:pat) => {};
diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs
index a59cacb8bde..039878af56e 100644
--- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs
+++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs
@@ -3,6 +3,5 @@
 // Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely.
 // `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`.
 #![feature(custom_inner_attributes)]
-//~^ ERROR `main` function not found in crate `issue_59191_replace_root_with_fn` [E0601]
 #![issue_59191::no_main]
 //~^ ERROR expected crate top-level item to be a module after macro expansion, found a function
diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr
index 5995a4891f3..579041c5259 100644
--- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr
+++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr
@@ -1,19 +1,10 @@
 error: expected crate top-level item to be a module after macro expansion, found a function
-  --> $DIR/issue-59191-replace-root-with-fn.rs:7:1
+  --> $DIR/issue-59191-replace-root-with-fn.rs:6:1
    |
 LL | #![issue_59191::no_main]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0601]: `main` function not found in crate `issue_59191_replace_root_with_fn`
-  --> $DIR/issue-59191-replace-root-with-fn.rs:5:1
-   |
-LL | / #![feature(custom_inner_attributes)]
-LL | |
-LL | | #![issue_59191::no_main]
-   | |________________________^ consider adding a `main` function to `$DIR/issue-59191-replace-root-with-fn.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
index 4c271a3916a..c16a6f8585b 100644
--- a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
+++ b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
@@ -23,7 +23,7 @@ error[E0597]: `self` does not live long enough
 LL |         let _f = || {
    |                  -- value captured here
 LL |             let p: &'static mut usize = &mut self.food;
-   |                    ------------------        ^^^^ borrowed value does not live long enough
+   |                    ------------------        ^^^^^^^^^ borrowed value does not live long enough
    |                    |
    |                    type annotation requires that `self` is borrowed for `'static`
 ...
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
index 194929fa287..5a66af1d29e 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
@@ -5,7 +5,6 @@
 
 #![allow(incomplete_features)]
 #![feature(const_trait_impl)]
-#![feature(const_fn)]
 
 struct NonConstAdd(i32);
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
index 8e6ef12810c..fa5570d5454 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
@@ -1,6 +1,5 @@
 #![allow(incomplete_features)]
 #![feature(const_trait_impl)]
-#![feature(const_fn)]
 
 pub trait Plus {
     fn plus(self, rhs: Self) -> Self;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
index 0c320d54c76..d3f350e1b61 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
@@ -1,5 +1,5 @@
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/call-const-trait-method-fail.rs:26:5
+  --> $DIR/call-const-trait-method-fail.rs:25:5
    |
 LL |     a.plus(b)
    |     ^^^^^^^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs
index 6a2112ea554..ec6f45f956d 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs
@@ -2,7 +2,6 @@
 
 #![allow(incomplete_features)]
 #![feature(const_trait_impl)]
-#![feature(const_fn)]
 
 struct Int(i32);
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
index 6d4bfe722de..dc4d5561d47 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn)]
+#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 #![feature(const_trait_bound_opt_out)]
 #![allow(incomplete_features)]
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs
index f0e32142221..1fc2c4fe445 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_fn)]
+#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 #![feature(const_trait_bound_opt_out)]
 #![allow(incomplete_features)]
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
index 2c8f6354dc6..9aefe6380cb 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
@@ -1,7 +1,6 @@
 // FIXME(jschievink): this is not rejected correctly (only when the non-const impl is actually used)
 // ignore-test
 
-#![feature(const_fn)]
 #![feature(const_trait_impl)]
 #![allow(incomplete_features)]
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
index 3506237d1f1..4452ad7ea23 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
@@ -4,7 +4,7 @@
 #![cfg_attr(gated, feature(const_trait_bound_opt_out))]
 #![allow(incomplete_features)]
 #![feature(rustc_attrs)]
-#![feature(const_fn)]
+#![feature(const_fn_trait_bound)]
 
 trait T {
     const CONST: i32;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs b/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs
index 655d4d7400b..ad14dd62bc7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs
@@ -1,6 +1,6 @@
 // Regression test for #69615.
 
-#![feature(const_trait_impl, const_fn)]
+#![feature(const_trait_impl)]
 #![allow(incomplete_features)]
 
 pub trait MyTrait {
diff --git a/src/test/ui/typeck/issue-75883.rs b/src/test/ui/typeck/issue-75883.rs
new file mode 100644
index 00000000000..3a59ca049ba
--- /dev/null
+++ b/src/test/ui/typeck/issue-75883.rs
@@ -0,0 +1,22 @@
+// Regression test for #75883.
+
+pub struct UI {}
+
+impl UI {
+    pub fn run() -> Result<_> {
+        //~^ ERROR: this enum takes 2 type arguments but only 1 type argument was supplied
+        //~| ERROR: the type placeholder `_` is not allowed within types on item signatures
+        let mut ui = UI {};
+        ui.interact();
+
+        unimplemented!();
+    }
+
+    pub fn interact(&mut self) -> Result<_> {
+        //~^ ERROR: this enum takes 2 type arguments but only 1 type argument was supplied
+        //~| ERROR: the type placeholder `_` is not allowed within types on item signatures
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-75883.stderr b/src/test/ui/typeck/issue-75883.stderr
new file mode 100644
index 00000000000..a6b2eb8f972
--- /dev/null
+++ b/src/test/ui/typeck/issue-75883.stderr
@@ -0,0 +1,52 @@
+error[E0107]: this enum takes 2 type arguments but only 1 type argument was supplied
+  --> $DIR/issue-75883.rs:6:21
+   |
+LL |     pub fn run() -> Result<_> {
+   |                     ^^^^^^ - supplied 1 type argument
+   |                     |
+   |                     expected 2 type arguments
+   |
+note: enum defined here, with 2 type parameters: `T`, `E`
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | pub enum Result<T, E> {
+   |          ^^^^^^ -  -
+help: add missing type argument
+   |
+LL |     pub fn run() -> Result<_, E> {
+   |                             ^^^
+
+error[E0107]: this enum takes 2 type arguments but only 1 type argument was supplied
+  --> $DIR/issue-75883.rs:15:35
+   |
+LL |     pub fn interact(&mut self) -> Result<_> {
+   |                                   ^^^^^^ - supplied 1 type argument
+   |                                   |
+   |                                   expected 2 type arguments
+   |
+note: enum defined here, with 2 type parameters: `T`, `E`
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | pub enum Result<T, E> {
+   |          ^^^^^^ -  -
+help: add missing type argument
+   |
+LL |     pub fn interact(&mut self) -> Result<_, E> {
+   |                                           ^^^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-75883.rs:15:42
+   |
+LL |     pub fn interact(&mut self) -> Result<_> {
+   |                                          ^ not allowed in type signatures
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-75883.rs:6:28
+   |
+LL |     pub fn run() -> Result<_> {
+   |                            ^ not allowed in type signatures
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0107, E0121.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/typeck/issue-80779.rs b/src/test/ui/typeck/issue-80779.rs
new file mode 100644
index 00000000000..6791976196f
--- /dev/null
+++ b/src/test/ui/typeck/issue-80779.rs
@@ -0,0 +1,13 @@
+// Regression test for #80779.
+
+pub struct T<'a>(&'a str);
+
+pub fn f<'a>(val: T<'a>) -> _ {
+    //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
+    g(val)
+}
+
+pub fn g(_: T<'static>) -> _ {}
+//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-80779.stderr b/src/test/ui/typeck/issue-80779.stderr
new file mode 100644
index 00000000000..aca494520f8
--- /dev/null
+++ b/src/test/ui/typeck/issue-80779.stderr
@@ -0,0 +1,21 @@
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-80779.rs:10:28
+   |
+LL | pub fn g(_: T<'static>) -> _ {}
+   |                            ^
+   |                            |
+   |                            not allowed in type signatures
+   |                            help: replace with the correct return type: `()`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-80779.rs:5:29
+   |
+LL | pub fn f<'a>(val: T<'a>) -> _ {
+   |                             ^
+   |                             |
+   |                             not allowed in type signatures
+   |                             help: replace with the correct return type: `()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 4369396ce7d270972955d876eaa4954bea56bcd
+Subproject f3e13226d6d17a2bc5f325303494b43a45f53b7
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index d951ca0e630..4676c2affad 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -44,7 +44,7 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str
     create_test(&lint).context("Unable to create a test for the new lint")
 }
 
-fn create_lint(lint: &LintData) -> io::Result<()> {
+fn create_lint(lint: &LintData<'_>) -> io::Result<()> {
     let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
         "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
         "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
@@ -68,7 +68,7 @@ fn create_lint(lint: &LintData) -> io::Result<()> {
     write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
 }
 
-fn create_test(lint: &LintData) -> io::Result<()> {
+fn create_test(lint: &LintData<'_>) -> io::Result<()> {
     fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
         let mut path = location.into().join(case);
         fs::create_dir(&path)?;
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 757d7669bd8..8c74284fa46 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -17,7 +17,7 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 // warn on rustc internal lints
-#![deny(rustc::internal)]
+#![warn(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index cd85c487798..e81a92eb74c 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -678,7 +678,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec
 pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
     cx.tcx
         .entry_fn(LOCAL_CRATE)
-        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
+        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
 }
 
 /// Returns `true` if the expression is in the program's `#[panic_handler]`.
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index fa0c5f01430..750a23e8c98 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -4,7 +4,7 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 // warn on rustc internal lints
-#![deny(rustc::internal)]
+#![warn(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index f4d354f0bf9..e1110721f6e 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -83,14 +83,7 @@ fn default_config() -> compiletest::Config {
         third_party_crates(),
     ));
 
-    config.build_base = if cargo::is_rustc_test_suite() {
-        // This make the stderr files go to clippy OUT_DIR on rustc repo build dir
-        let mut path = PathBuf::from(env!("OUT_DIR"));
-        path.push("test_build_base");
-        path
-    } else {
-        host_lib().join("test_build_base")
-    };
+    config.build_base = host_lib().join("test_build_base");
     config.rustc_path = clippy_driver_path();
     config
 }
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 5faf5a5ca059f6eb067fc86e47480f5668ac6e8
+Subproject 41f3fe64317a6ef144d2ac33e4e5870d894d603
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 7570212a544b8e973a7d57be3657aae6465028a
+Subproject 617535393bb5ccc7adf0bac8a3b9a9c306454e7
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index cb84fd8be6f..b14b5aeb572 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -423,6 +423,15 @@ fn map_lib_features(
                         continue;
                     }};
                 }
+
+                lazy_static::lazy_static! {
+                    static ref COMMENT_LINE: Regex = Regex::new(r"^\s*//").unwrap();
+                }
+                // exclude commented out lines
+                if COMMENT_LINE.is_match(line) {
+                    continue;
+                }
+
                 if let Some((ref name, ref mut f)) = becoming_feature {
                     if f.tracking_issue.is_none() {
                         f.tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none);
diff --git a/src/version b/src/version
index 3f4830156cb..b7921ae87bc 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.53.0
+1.54.0