about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock225
-rw-r--r--RELEASES.md148
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs56
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs39
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs35
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs14
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs64
-rw-r--r--compiler/rustc_codegen_llvm/src/metadata.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs81
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs130
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs7
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0782.md26
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0783.md22
-rw-r--r--compiler/rustc_errors/src/lib.rs27
-rw-r--r--compiler/rustc_expand/src/module.rs23
-rw-r--r--compiler/rustc_feature/src/active.rs20
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs8
-rw-r--r--compiler/rustc_hir/src/definitions.rs5
-rw-r--r--compiler/rustc_index/src/bit_set.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs3
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs3
-rw-r--r--compiler/rustc_interface/src/tests.rs173
-rw-r--r--compiler/rustc_lint/src/builtin.rs85
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs6
-rw-r--r--compiler/rustc_metadata/src/dynamic_lib.rs6
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs122
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs15
-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/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs12
-rw-r--r--compiler/rustc_middle/src/middle/cstore.rs1
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs13
-rw-r--r--compiler/rustc_middle/src/mir/query.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs11
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs20
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs1
-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.rs3
-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/interpret/intrinsics.rs44
-rw-r--r--compiler/rustc_mir/src/interpret/machine.rs1
-rw-r--r--compiler/rustc_mir/src/interpret/memory.rs10
-rw-r--r--compiler/rustc_mir/src/interpret/place.rs2
-rw-r--r--compiler/rustc_mir/src/interpret/step.rs34
-rw-r--r--compiler/rustc_mir/src/interpret/validity.rs10
-rw-r--r--compiler/rustc_mir/src/transform/coverage/mod.rs27
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs14
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs39
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs4
-rw-r--r--compiler/rustc_query_system/src/query/config.rs4
-rw-r--r--compiler/rustc_query_system/src/query/job.rs21
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs196
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs43
-rw-r--r--compiler/rustc_session/src/config.rs271
-rw-r--r--compiler/rustc_session/src/options.rs898
-rw-r--r--compiler/rustc_session/src/utils.rs33
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
-rw-r--r--compiler/rustc_span/src/lib.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs6
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/dragonfly_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/haiku_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/linux_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs32
-rw-r--r--compiler/rustc_target/src/spec/netbsd_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/redox_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/solaris_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/vxworks_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/windows_msvc_base.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs14
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs6
-rw-r--r--compiler/rustc_type_ir/src/lib.rs15
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs6
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs67
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs6
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs15
-rw-r--r--compiler/rustc_typeck/src/collect.rs28
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs20
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs4
-rw-r--r--library/alloc/src/alloc.rs9
-rw-r--r--library/alloc/src/borrow.rs9
-rw-r--r--library/alloc/src/boxed.rs37
-rw-r--r--library/alloc/src/collections/btree/map.rs30
-rw-r--r--library/alloc/src/collections/mod.rs11
-rw-r--r--library/alloc/src/fmt.rs2
-rw-r--r--library/alloc/src/lib.rs4
-rw-r--r--library/alloc/src/raw_vec.rs16
-rw-r--r--library/alloc/src/rc.rs38
-rw-r--r--library/alloc/src/slice.rs32
-rw-r--r--library/alloc/src/str.rs13
-rw-r--r--library/alloc/src/string.rs121
-rw-r--r--library/alloc/src/sync.rs38
-rw-r--r--library/alloc/src/vec/into_iter.rs2
-rw-r--r--library/alloc/src/vec/mod.rs56
-rw-r--r--library/alloc/src/vec/partial_eq.rs4
-rw-r--r--library/core/src/cmp.rs5
-rw-r--r--library/core/src/hint.rs2
-rw-r--r--library/core/src/intrinsics.rs26
-rw-r--r--library/core/src/lib.rs5
-rw-r--r--library/core/src/mem/maybe_uninit.rs4
-rw-r--r--library/core/src/num/bignum.rs4
-rw-r--r--library/core/src/ptr/const_ptr.rs6
-rw-r--r--library/core/src/ptr/mod.rs85
-rw-r--r--library/core/src/ptr/mut_ptr.rs12
-rw-r--r--library/core/src/ptr/non_null.rs2
-rw-r--r--library/core/src/slice/mod.rs5
-rw-r--r--library/core/src/time.rs10
-rw-r--r--library/panic_unwind/src/seh.rs2
-rw-r--r--library/std/src/collections/hash/map.rs30
-rw-r--r--library/std/src/env.rs1
-rw-r--r--library/std/src/ffi/c_str.rs2
-rw-r--r--library/std/src/io/buffered/bufwriter.rs217
-rw-r--r--library/std/src/io/error.rs6
-rw-r--r--library/std/src/net/udp.rs4
-rw-r--r--library/std/src/os/fortanix_sgx/arch.rs (renamed from library/std/src/sys/sgx/ext/arch.rs)0
-rw-r--r--library/std/src/os/fortanix_sgx/ffi.rs (renamed from library/std/src/sys/sgx/ext/ffi.rs)0
-rw-r--r--library/std/src/os/fortanix_sgx/io.rs (renamed from library/std/src/sys/sgx/ext/io.rs)0
-rw-r--r--library/std/src/os/fortanix_sgx/mod.rs6
-rw-r--r--library/std/src/os/hermit/ffi.rs (renamed from library/std/src/sys/hermit/ext/ffi.rs)0
-rw-r--r--library/std/src/os/hermit/mod.rs (renamed from library/std/src/sys/hermit/ext/mod.rs)1
-rw-r--r--library/std/src/os/linux/mod.rs1
-rw-r--r--library/std/src/os/linux/raw.rs1
-rw-r--r--library/std/src/os/mod.rs169
-rw-r--r--library/std/src/os/redox/raw.rs1
-rw-r--r--library/std/src/os/unix/ffi.rs (renamed from library/std/src/sys/unix/ext/ffi.rs)0
-rw-r--r--library/std/src/os/unix/fs.rs (renamed from library/std/src/sys/unix/ext/fs.rs)0
-rw-r--r--library/std/src/os/unix/io.rs (renamed from library/std/src/sys/unix/ext/io.rs)0
-rw-r--r--library/std/src/os/unix/mod.rs (renamed from library/std/src/sys/unix/ext/mod.rs)73
-rw-r--r--library/std/src/os/unix/net/addr.rs (renamed from library/std/src/sys/unix/ext/net/addr.rs)0
-rw-r--r--library/std/src/os/unix/net/ancillary.rs (renamed from library/std/src/sys/unix/ext/net/ancillary.rs)4
-rw-r--r--library/std/src/os/unix/net/datagram.rs (renamed from library/std/src/sys/unix/ext/net/datagram.rs)0
-rw-r--r--library/std/src/os/unix/net/listener.rs (renamed from library/std/src/sys/unix/ext/net/listener.rs)0
-rw-r--r--library/std/src/os/unix/net/mod.rs (renamed from library/std/src/sys/unix/ext/net/mod.rs)0
-rw-r--r--library/std/src/os/unix/net/raw_fd.rs (renamed from library/std/src/sys/unix/ext/net/raw_fd.rs)0
-rw-r--r--library/std/src/os/unix/net/stream.rs (renamed from library/std/src/sys/unix/ext/net/stream.rs)0
-rw-r--r--library/std/src/os/unix/net/tests.rs (renamed from library/std/src/sys/unix/ext/net/tests.rs)0
-rw-r--r--library/std/src/os/unix/process.rs (renamed from library/std/src/sys/unix/ext/process.rs)0
-rw-r--r--library/std/src/os/unix/raw.rs (renamed from library/std/src/sys/unix/ext/raw.rs)0
-rw-r--r--library/std/src/os/unix/thread.rs (renamed from library/std/src/sys/unix/ext/thread.rs)0
-rw-r--r--library/std/src/os/unix/ucred.rs (renamed from library/std/src/sys/unix/ext/ucred.rs)0
-rw-r--r--library/std/src/os/unix/ucred/tests.rs (renamed from library/std/src/sys/unix/ext/ucred/tests.rs)0
-rw-r--r--library/std/src/os/wasi.rs6
-rw-r--r--library/std/src/os/wasi/ffi.rs (renamed from library/std/src/sys/wasi/ext/ffi.rs)0
-rw-r--r--library/std/src/os/wasi/fs.rs (renamed from library/std/src/sys/wasi/ext/fs.rs)0
-rw-r--r--library/std/src/os/wasi/io.rs (renamed from library/std/src/sys/wasi/ext/io.rs)0
-rw-r--r--library/std/src/os/wasi/mod.rs (renamed from library/std/src/sys/wasi/ext/mod.rs)1
-rw-r--r--library/std/src/os/windows/ffi.rs (renamed from library/std/src/sys/windows/ext/ffi.rs)0
-rw-r--r--library/std/src/os/windows/fs.rs (renamed from library/std/src/sys/windows/ext/fs.rs)0
-rw-r--r--library/std/src/os/windows/io.rs (renamed from library/std/src/sys/windows/ext/io.rs)0
-rw-r--r--library/std/src/os/windows/mod.rs (renamed from library/std/src/sys/windows/ext/mod.rs)1
-rw-r--r--library/std/src/os/windows/process.rs (renamed from library/std/src/sys/windows/ext/process.rs)0
-rw-r--r--library/std/src/os/windows/raw.rs (renamed from library/std/src/sys/windows/ext/raw.rs)0
-rw-r--r--library/std/src/os/windows/thread.rs (renamed from library/std/src/sys/windows/ext/thread.rs)0
-rw-r--r--library/std/src/primitive_docs.rs22
-rw-r--r--library/std/src/sys/hermit/mod.rs1
-rw-r--r--library/std/src/sys/mod.rs81
-rw-r--r--library/std/src/sys/sgx/abi/mod.rs6
-rw-r--r--library/std/src/sys/sgx/ext/mod.rs5
-rw-r--r--library/std/src/sys/sgx/mod.rs1
-rw-r--r--library/std/src/sys/sgx/thread.rs69
-rw-r--r--library/std/src/sys/unix/fs.rs4
-rw-r--r--library/std/src/sys/unix/mod.rs2
-rw-r--r--library/std/src/sys/unix/os.rs8
-rw-r--r--library/std/src/sys/unix/process/process_common.rs2
-rw-r--r--library/std/src/sys/wasi/mod.rs2
-rw-r--r--library/std/src/sys/windows/c.rs2
-rw-r--r--library/std/src/sys/windows/mod.rs2
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--library/std/src/thread/local/tests.rs108
-rw-r--r--src/bootstrap/bootstrap.py12
-rw-r--r--src/bootstrap/builder/tests.rs3
-rw-r--r--src/bootstrap/check.rs6
-rw-r--r--src/bootstrap/flags.rs14
-rw-r--r--src/bootstrap/test.rs39
-rw-r--r--src/bootstrap/tool.rs5
-rwxr-xr-xsrc/ci/scripts/install-clang.sh27
-rw-r--r--src/doc/rustc/src/platform-support.md4
-rw-r--r--src/doc/rustc/src/target-tier-policy.md10
-rw-r--r--src/doc/unstable-book/src/compiler-flags/instrument-coverage.md346
-rw-r--r--src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md326
-rw-r--r--src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md18
-rw-r--r--src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md19
-rw-r--r--src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md20
-rw-r--r--src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md18
-rw-r--r--src/doc/unstable-book/src/language-features/native-link-modifiers.md11
-rw-r--r--src/doc/unstable-book/src/language-features/no-coverage.md30
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/inline.rs26
-rw-r--r--src/librustdoc/clean/mod.rs44
-rw-r--r--src/librustdoc/clean/types.rs159
-rw-r--r--src/librustdoc/clean/utils.rs40
-rw-r--r--src/librustdoc/clean/utils/tests.rs41
-rw-r--r--src/librustdoc/config.rs10
-rw-r--r--src/librustdoc/core.rs77
-rw-r--r--src/librustdoc/doctest.rs3
-rw-r--r--src/librustdoc/doctree.rs13
-rw-r--r--src/librustdoc/formats/cache.rs75
-rw-r--r--src/librustdoc/formats/mod.rs4
-rw-r--r--src/librustdoc/html/format.rs15
-rw-r--r--src/librustdoc/html/highlight.rs41
-rw-r--r--src/librustdoc/html/highlight/tests.rs27
-rw-r--r--src/librustdoc/html/render/cache.rs10
-rw-r--r--src/librustdoc/html/render/context.rs5
-rw-r--r--src/librustdoc/html/render/mod.rs212
-rw-r--r--src/librustdoc/html/render/print_item.rs30
-rw-r--r--src/librustdoc/html/render/write_shared.rs4
-rw-r--r--src/librustdoc/html/sources.rs2
-rw-r--r--src/librustdoc/html/static/main.js97
-rw-r--r--src/librustdoc/html/static/rustdoc.css49
-rw-r--r--src/librustdoc/html/static/themes/ayu.css3
-rw-r--r--src/librustdoc/html/static/themes/dark.css3
-rw-r--r--src/librustdoc/html/static/themes/light.css3
-rw-r--r--src/librustdoc/json/conversions.rs22
-rw-r--r--src/librustdoc/json/mod.rs15
-rw-r--r--src/librustdoc/lib.rs8
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs6
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs105
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs22
-rw-r--r--src/librustdoc/passes/doc_test_lints.rs5
-rw-r--r--src/librustdoc/passes/strip_hidden.rs7
-rw-r--r--src/librustdoc/passes/strip_private.rs6
-rw-r--r--src/librustdoc/passes/stripper.rs17
-rw-r--r--src/librustdoc/theme.rs2
-rw-r--r--src/librustdoc/visit_ast.rs15
-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/debuginfo/generator-objects.rs20
-rw-r--r--src/test/debuginfo/issue-57822.rs4
-rw-r--r--src/test/debuginfo/should-fail.rs1
-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/ast-stmt-expr-attr.rs30
-rw-r--r--src/test/pretty/stmt_expr_attributes.rs59
-rw-r--r--src/test/run-make-fulldeps/alloc-extern-crates/Makefile5
-rw-r--r--src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs25
-rw-r--r--src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile4
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt12
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt106
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt14
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt14
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt27
-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.panic_unwind.txt18
-rw-r--r--src/test/run-make-fulldeps/coverage/async2.rs12
-rw-r--r--src/test/run-make-fulldeps/coverage/closure.rs76
-rw-r--r--src/test/run-make-fulldeps/coverage/closure_macro.rs2
-rw-r--r--src/test/run-make-fulldeps/coverage/closure_macro_async.rs2
-rw-r--r--src/test/run-make-fulldeps/coverage/no_cov_crate.rs19
-rw-r--r--src/test/run-make-fulldeps/coverage/no_cov_func.rs18
-rw-r--r--src/test/run-make-fulldeps/coverage/panic_unwind.rs18
-rw-r--r--src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr1
-rw-r--r--src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr11
-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/assoc-consts.rs6
-rw-r--r--src/test/rustdoc/auxiliary/trait-alias-mention.rs3
-rw-r--r--src/test/rustdoc/auxiliary/trait-visibility.rs3
-rw-r--r--src/test/rustdoc/inline_cross/assoc-items.rs9
-rw-r--r--src/test/rustdoc/inline_cross/impl-inline-without-trait.rs3
-rw-r--r--src/test/rustdoc/manual_impl.rs23
-rw-r--r--src/test/rustdoc/trait-alias-mention.rs10
-rw-r--r--src/test/rustdoc/trait-impl.rs31
-rw-r--r--src/test/rustdoc/trait-visibility.rs8
-rw-r--r--src/test/rustdoc/trait_alias.rs2
-rw-r--r--src/test/ui/async-await/async-borrowck-escaping-block-error.stderr6
-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/cfg/cfg-family.rs4
-rw-r--r--src/test/ui/cfg/cfg-panic.rs1
-rw-r--r--src/test/ui/cfg/cfg-target-family.rs7
-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/const-param-type-depends-on-type-param.full.stderr1
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr1
-rw-r--r--src/test/ui/const-generics/issue-67375.full.stderr1
-rw-r--r--src/test/ui/const-generics/issue-67375.min.stderr1
-rw-r--r--src/test/ui/const-generics/issue-67945-1.full.stderr1
-rw-r--r--src/test/ui/const-generics/issue-67945-1.min.stderr1
-rw-r--r--src/test/ui/const-generics/issue-67945-2.full.stderr1
-rw-r--r--src/test/ui/const-generics/issue-67945-2.min.stderr1
-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/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs1
-rw-r--r--src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr22
-rw-r--r--src/test/ui/const-generics/unused-type-param-suggestion.rs4
-rw-r--r--src/test/ui/const-generics/unused-type-param-suggestion.stderr12
-rw-r--r--src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-nonnull.rs2
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-upvars.32bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-upvars.64bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr2
-rw-r--r--src/test/ui/consts/offset_from_ub.stderr2
-rw-r--r--src/test/ui/consts/offset_ub.stderr8
-rw-r--r--src/test/ui/consts/ptr_comparisons.stderr2
-rw-r--r--src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs16
-rw-r--r--src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr34
-rw-r--r--src/test/ui/dyn-keyword/dyn-2021-edition-error.rs12
-rw-r--r--src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr36
-rw-r--r--src/test/ui/empty/empty-struct-unit-pat.stderr102
-rw-r--r--src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr1
-rw-r--r--src/test/ui/enum/issue-67945-1.stderr1
-rw-r--r--src/test/ui/enum/issue-67945-2.stderr1
-rw-r--r--src/test/ui/error-codes/E0392.stderr1
-rw-r--r--src/test/ui/error-codes/E0504.stderr2
-rw-r--r--src/test/ui/error-codes/E0583.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs5
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-no_coverage.rs13
-rw-r--r--src/test/ui/feature-gates/feature-gate-no_coverage.stderr3
-rw-r--r--src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-static-nobundle.rs3
-rw-r--r--src/test/ui/feature-gates/feature-gate-static-nobundle.stderr8
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.stderr2
-rw-r--r--src/test/ui/generator/yield-while-ref-reborrowed.stderr2
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs1
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr2
-rw-r--r--src/test/ui/inner-static-type-parameter.stderr1
-rw-r--r--src/test/ui/intrinsics/intrinsic-alignment.rs1
-rw-r--r--src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr2
-rw-r--r--src/test/ui/issues/issue-11192.stderr2
-rw-r--r--src/test/ui/issues/issue-17904-2.stderr1
-rw-r--r--src/test/ui/issues/issue-20413.stderr1
-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-32004.stderr5
-rw-r--r--src/test/ui/issues/issue-36299.stderr1
-rw-r--r--src/test/ui/issues/issue-36638.stderr1
-rw-r--r--src/test/ui/issues/issue-37534.stderr1
-rw-r--r--src/test/ui/issues/issue-47412.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/issues/issue-70093.rs1
-rw-r--r--src/test/ui/issues/issue-pr29383.stderr10
-rw-r--r--src/test/ui/lifetimes/issue-84398.rs20
-rw-r--r--src/test/ui/lint/bare-trait-objects-path.rs12
-rw-r--r--src/test/ui/lint/bare-trait-objects-path.stderr14
-rw-r--r--src/test/ui/lint/expr_attr_paren_order.rs6
-rw-r--r--src/test/ui/lint/expr_attr_paren_order.stderr8
-rw-r--r--src/test/ui/lint/inclusive-range-pattern-syntax.fixed2
-rw-r--r--src/test/ui/lint/inclusive-range-pattern-syntax.rs2
-rw-r--r--src/test/ui/lint/inclusive-range-pattern-syntax.stderr7
-rw-r--r--src/test/ui/match/match-pattern-field-mismatch-2.stderr5
-rw-r--r--src/test/ui/meta/revision-bad.rs1
-rw-r--r--src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr2
-rw-r--r--src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr2
-rw-r--r--src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr2
-rw-r--r--src/test/ui/native-library-link-flags/empty-kind-1.rs6
-rw-r--r--src/test/ui/native-library-link-flags/empty-kind-1.stderr2
-rw-r--r--src/test/ui/native-library-link-flags/empty-kind-2.rs6
-rw-r--r--src/test/ui/native-library-link-flags/empty-kind-2.stderr2
-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/panic-handler/weak-lang-item.rs1
-rw-r--r--src/test/ui/panic-handler/weak-lang-item.stderr2
-rw-r--r--src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs1
-rw-r--r--src/test/ui/panic-runtime/lto-unwind.rs1
-rw-r--r--src/test/ui/panic-runtime/transitive-link-a-bunch.rs1
-rw-r--r--src/test/ui/panic-runtime/want-unwind-got-abort.rs1
-rw-r--r--src/test/ui/panic-runtime/want-unwind-got-abort2.rs1
-rw-r--r--src/test/ui/parser/issue-68890-2.rs1
-rw-r--r--src/test/ui/parser/issue-68890-2.stderr2
-rw-r--r--src/test/ui/parser/issue-73568-lifetime-after-mut.rs2
-rw-r--r--src/test/ui/parser/issue-73568-lifetime-after-mut.stderr9
-rw-r--r--src/test/ui/parser/macro/trait-object-macro-matcher.rs1
-rw-r--r--src/test/ui/parser/macro/trait-object-macro-matcher.stderr2
-rw-r--r--src/test/ui/parser/mod_file_not_exist.stderr2
-rw-r--r--src/test/ui/parser/mod_file_not_exist_windows.stderr2
-rw-r--r--src/test/ui/parser/recover-range-pats.rs21
-rw-r--r--src/test/ui/parser/recover-range-pats.stderr119
-rw-r--r--src/test/ui/parser/stmt_expr_attrs_placement.rs16
-rw-r--r--src/test/ui/parser/stmt_expr_attrs_placement.stderr58
-rw-r--r--src/test/ui/parser/trait-object-delimiters.rs17
-rw-r--r--src/test/ui/parser/trait-object-delimiters.stderr77
-rw-r--r--src/test/ui/parser/trait-object-trait-parens.rs7
-rw-r--r--src/test/ui/parser/trait-object-trait-parens.stderr52
-rw-r--r--src/test/ui/parser/unsafe-mod.stderr2
-rw-r--r--src/test/ui/pattern/pattern-error-continue.stderr16
-rw-r--r--src/test/ui/proc-macro/inner-attrs.rs32
-rw-r--r--src/test/ui/proc-macro/inner-attrs.stderr40
-rw-r--r--src/test/ui/proc-macro/inner-attrs.stdout557
-rw-r--r--src/test/ui/proc-macro/simple-tuple.rs19
-rw-r--r--src/test/ui/proc-macro/simple-tuple.stdout79
-rw-r--r--src/test/ui/range/exclusive-range-patterns-2021.rs14
-rw-r--r--src/test/ui/range/exclusive-range-patterns-2021.stderr27
-rw-r--r--src/test/ui/range/range-inclusive-pattern-precedence.fixed3
-rw-r--r--src/test/ui/range/range-inclusive-pattern-precedence.rs3
-rw-r--r--src/test/ui/range/range-inclusive-pattern-precedence.stderr4
-rw-r--r--src/test/ui/range/range-inclusive-pattern-precedence2.rs1
-rw-r--r--src/test/ui/range/range-inclusive-pattern-precedence2.stderr4
-rw-r--r--src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr2
-rw-r--r--src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr2
-rw-r--r--src/test/ui/rust-2018/suggestions-not-always-applicable.fixed8
-rw-r--r--src/test/ui/rust-2018/suggestions-not-always-applicable.rs8
-rw-r--r--src/test/ui/rust-2018/suggestions-not-always-applicable.stderr28
-rw-r--r--src/test/ui/structs-enums/rec-align-u64.rs1
-rw-r--r--src/test/ui/suggestions/import-trait-for-method-call.rs9
-rw-r--r--src/test/ui/suggestions/import-trait-for-method-call.stderr18
-rw-r--r--src/test/ui/suggestions/issue-61963.rs4
-rw-r--r--src/test/ui/suggestions/issue-61963.stderr7
-rw-r--r--src/test/ui/suggestions/issue-84700.rs26
-rw-r--r--src/test/ui/suggestions/issue-84700.stderr21
-rw-r--r--src/test/ui/suggestions/unsized-function-parameter.fixed23
-rw-r--r--src/test/ui/suggestions/unsized-function-parameter.rs23
-rw-r--r--src/test/ui/suggestions/unsized-function-parameter.stderr42
-rw-r--r--src/test/ui/test-panic-abort-disabled.rs2
-rw-r--r--src/test/ui/traits/bound/not-on-bare-trait.rs5
-rw-r--r--src/test/ui/traits/bound/not-on-bare-trait.stderr2
-rw-r--r--src/test/ui/traits/issue-84399-bad-fresh-caching.rs55
-rw-r--r--src/test/ui/traits/safety-fn-body.stderr2
-rw-r--r--src/test/ui/typeck/issue-84831.rs9
-rw-r--r--src/test/ui/typeck/issue-84831.stderr26
-rw-r--r--src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr2
-rw-r--r--src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr4
-rw-r--r--src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr2
-rw-r--r--src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr2
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.stderr2
-rw-r--r--src/test/ui/unwind-no-uwtable.rs1
-rw-r--r--src/test/ui/variance/variance-unused-type-param.stderr3
-rw-r--r--src/test/ui/x86stdcall.rs1
-rw-r--r--src/tools/cargotest/main.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3969.stderr8
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs1
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr2
-rw-r--r--src/tools/compiletest/src/common.rs22
-rw-r--r--src/tools/compiletest/src/header.rs12
-rw-r--r--src/tools/compiletest/src/main.rs25
-rw-r--r--src/tools/compiletest/src/runtest.rs62
-rw-r--r--src/tools/lint-docs/src/groups.rs1
m---------src/tools/miri17
m---------src/tools/rls0
m---------src/tools/rust-analyzer36
m---------src/tools/rustfmt10
-rw-r--r--src/tools/tidy/src/deps.rs185
514 files changed, 7223 insertions, 4204 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a55ef7b6143..77b917448e9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -60,18 +60,12 @@ dependencies = [
 
 [[package]]
 name = "annotate-snippets"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
-dependencies = [
- "ansi_term 0.11.0",
-]
-
-[[package]]
-name = "annotate-snippets"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5"
+dependencies = [
+ "yansi-term",
+]
 
 [[package]]
 name = "ansi_term"
@@ -105,12 +99,6 @@ checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
 
 [[package]]
 name = "arrayvec"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
-
-[[package]]
-name = "arrayvec"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7"
@@ -876,24 +864,24 @@ dependencies = [
 
 [[package]]
 name = "curl"
-version = "0.4.34"
+version = "0.4.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e268162af1a5fe89917ae25ba3b0a77c8da752bdc58e7dbb4f15b91fbd33756e"
+checksum = "d0bac9f84ca0977c4d9b8db998689de55b9e976656a6bc87fada2ca710d504c7"
 dependencies = [
  "curl-sys",
  "libc",
  "openssl-probe",
  "openssl-sys",
  "schannel",
- "socket2",
+ "socket2 0.4.0",
  "winapi 0.3.9",
 ]
 
 [[package]]
 name = "curl-sys"
-version = "0.4.39+curl-7.74.0"
+version = "0.4.42+curl-7.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07a8ce861e7b68a0b394e814d7ee9f1b2750ff8bd10372c6ad3bacc10e86f874"
+checksum = "4636d8d6109c842707018a104051436bffb8991ea20b2d1293db70b6e0ee4c7c"
 dependencies = [
  "cc",
  "libc",
@@ -2285,7 +2273,7 @@ version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
 dependencies = [
- "socket2",
+ "socket2 0.3.16",
  "winapi 0.3.9",
 ]
 
@@ -2402,15 +2390,15 @@ dependencies = [
 
 [[package]]
 name = "openssl"
-version = "0.10.30"
+version = "0.10.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
+checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577"
 dependencies = [
  "bitflags",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "foreign-types",
- "lazy_static",
  "libc",
+ "once_cell",
  "openssl-sys",
 ]
 
@@ -2422,18 +2410,18 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
 
 [[package]]
 name = "openssl-src"
-version = "111.12.0+1.1.1h"
+version = "111.15.0+1.1.1k"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61"
+checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.58"
+version = "0.9.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
+checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f"
 dependencies = [
  "autocfg",
  "cc",
@@ -2856,9 +2844,9 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.45"
+version = "2.1.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15408926f6207643150e0fc2c54a75a689b192df03ac6c59d42ea99c6782c7f7"
+checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1"
 dependencies = [
  "bitflags",
  "clap",
@@ -3221,9 +3209,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_arena"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "259cca0e975ecb05fd289ace45280c30ff792efc04e856a7f18b7fc86a3cb610"
+checksum = "526610f47139efa440178239553b59ea805ff57a532b4e295c71d2a9b18fd676"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "smallvec",
@@ -3231,9 +3219,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_ast"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb9be435d50c88e94bbad6ea468c8680b52c5043bb298ab8058d05251717f8f8"
+checksum = "cf6a9dda0804a7243b0282e3b75a8cf4654c7a61f033e587751941e1fe39391b"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3247,29 +3235,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc-ap-rustc_ast_passes"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75246dd1a95a57f7767e53bde3971baa2d948078e180564709f5ea46cf863ddd"
-dependencies = [
- "itertools 0.9.0",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_attr",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
- "tracing",
-]
-
-[[package]]
 name = "rustc-ap-rustc_ast_pretty"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79bede0b44bed453fd0034b7ba492840391f6486bf3e17a1af12922f0b98d4cc"
+checksum = "82f5019be8b41a58664169fd2f4b1a37fe82705681db394b76419e4e87d40ab1"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_span",
@@ -3277,38 +3246,21 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc-ap-rustc_attr"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84a92a4a34b996694ca2dab70361c60d2d48c07adce57e8155b7ec75e069e3ea"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
-]
-
-[[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cbfa7f82517a1b2efe7106c864c3f930b1da8aff07a27fd317af2f36522fd2e"
+checksum = "a701717fb14549331085756b9741ae3b4bf35808489f1887d72c1d0e0fe52b77"
 dependencies = [
- "arrayvec 0.5.2",
+ "arrayvec",
  "bitflags",
  "cfg-if 0.1.10",
- "crossbeam-utils 0.7.2",
+ "crossbeam-utils 0.8.3",
  "ena",
  "indexmap",
  "jobserver",
  "libc",
  "measureme",
+ "memmap2",
  "parking_lot",
  "rustc-ap-rustc_graphviz",
  "rustc-ap-rustc_index",
@@ -3327,11 +3279,11 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58a272a5101843bcb40900cc9ccf80ecfec62830bb1f4a242986da4a34c0da89"
+checksum = "e3182ce85e8bfc96443475547f2f5aa2b5e67655d9b88721795f36f0ba9e265a"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "atty",
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_lint_defs",
@@ -3346,34 +3298,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc-ap-rustc_expand"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bc7988f3facf2402fe057405ef0f7fbacc7e7a483da25e35a35ac09491fbbfb"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_passes",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_attr",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_lint_defs",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
- "smallvec",
- "tracing",
-]
-
-[[package]]
 name = "rustc-ap-rustc_feature"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e931cd1580ae60c5737d3fa57633034935e885414e794d83b3e52a81021985c"
+checksum = "eed033b93270126ef60963c3ebbd0e026bf53b985172b6366c7b0e7881c9d507"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_span",
@@ -3381,41 +3309,41 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_fs_util"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fe9422e10d5b441d2a78202667bc85d7cf713a087b9ae6cdea0dfc825d79f07"
+checksum = "28ee6531986a205101e09fd143d7bf31897388f33b1814d4bcc45fd62211dca6"
 
 [[package]]
 name = "rustc-ap-rustc_graphviz"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffffffdef9fd51db69c1d4c045ced8aaab999be5627f2d3a0ce020d74c1f1e50"
+checksum = "3398fddc0e23d2db89c036f8952ddf78cadc597f7059752116e69483e164a5b6"
 
 [[package]]
 name = "rustc-ap-rustc_index"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f6f53afc4f7111c82295cb7ea3878f520bbac6a2c5a12e125b4ca9156498cff"
+checksum = "dca4e27eb5b701f6bbd47d8fc9d242378fca3e4107a519a28415c2989c4a3bd3"
 dependencies = [
- "arrayvec 0.5.2",
+ "arrayvec",
  "rustc-ap-rustc_macros",
  "rustc-ap-rustc_serialize",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8056b05346dff7e39164d0434c6ec443a14ab5fbf6221bd1a56e5abbeae5f60c"
+checksum = "786bbfe9d4d5264294c1819dbf1497a2480b583d5eda1ca9ae22e12d6661f5df"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_lint_defs"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "364c3fb7b3cbdfe3fbb21d4078ff2cb3c58df63cda27995f8b064d21ee6dede5"
+checksum = "be2f045e2b999c154ec505d5fea69c994b742f3ebd2f552d11a6c81723921e47"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_data_structures",
@@ -3428,9 +3356,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_macros"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4607d6879cae3bae4d0369ca4b3a7510fd6295ac32eec088ac975208ba96ca45"
+checksum = "27789cd26d6b9e2fdfa68a262a20664d79ca67d31a3886d40fb88ebf6935869c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3440,9 +3368,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_parse"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78d22889bff7ca2346037c9df7ea55c66ffb714f5b50fb62b41975f8ac7a2d70"
+checksum = "1dc331f4958350679679e619d63a891e8d5d34ef99087068c89aa9e657d52caa"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_ast",
@@ -3460,9 +3388,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_serialize"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d33c710120953c0214f47a6caf42064d7e241003b4af36c98a6d6156e70335f1"
+checksum = "e9a6824a462c4c1a379e911b0faf86d303a54bcf8673d4cc445195085966a4a4"
 dependencies = [
  "indexmap",
  "smallvec",
@@ -3470,9 +3398,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_session"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d35919041429a90713c8f704fa5209ba159cb554ce74d95722cbc18ac4b4c6f"
+checksum = "a782a5f6ada0dbe089c6416ad0104f0b8a8bdb4bd26ea95e5fefaec67aed5e8a"
 dependencies = [
  "bitflags",
  "getopts",
@@ -3492,9 +3420,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_span"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73b12170c69603c0bf4b50e5c25fd348aae13b8c6465aa0ef4389c9eaa568e51"
+checksum = "a257546cb264b250c7abdb81239bb02f18a274a966211755a3ea89411b122214"
 dependencies = [
  "cfg-if 0.1.10",
  "md-5",
@@ -3512,9 +3440,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_target"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a8329d92e7dc24b974f759e6c6e97e2bbc47b18d0573343028f8135ca367200"
+checksum = "b5a72dd689421bcb5750f3ed0dedf367076e714ef0ba56c02ed391b9a8582862"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3797,7 +3725,7 @@ dependencies = [
 name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
  "bitflags",
  "cfg-if 0.1.10",
  "crossbeam-utils 0.8.3",
@@ -3866,7 +3794,7 @@ version = "0.0.0"
 name = "rustc_errors"
 version = "0.0.0"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "atty",
  "rustc_data_structures",
  "rustc_lint_defs",
@@ -3967,7 +3895,7 @@ dependencies = [
 name = "rustc_index"
 version = "0.0.0"
 dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
  "rustc_macros",
  "rustc_serialize",
 ]
@@ -4563,7 +4491,7 @@ dependencies = [
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
  "expect-test",
  "itertools 0.9.0",
  "minifier",
@@ -4625,7 +4553,7 @@ dependencies = [
 name = "rustfmt-nightly"
 version = "1.4.37"
 dependencies = [
- "annotate-snippets 0.6.1",
+ "annotate-snippets",
  "anyhow",
  "bytecount",
  "cargo_metadata 0.8.2",
@@ -4639,14 +4567,6 @@ dependencies = [
  "lazy_static",
  "log",
  "regex",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_expand",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
  "rustc-workspace-hack",
  "rustfmt-config_proc_macro",
  "serde",
@@ -4944,6 +4864,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "socket2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
+dependencies = [
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
 name = "stable_deref_trait"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5796,3 +5726,12 @@ checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
 dependencies = [
  "linked-hash-map",
 ]
+
+[[package]]
+name = "yansi-term"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
+dependencies = [
+ "winapi 0.3.9",
+]
diff --git a/RELEASES.md b/RELEASES.md
index 024610bc7a4..1f940e6bc2d 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,151 @@
+Version 1.52.0 (2021-05-06)
+============================
+
+Language
+--------
+- [Added the `unsafe_op_in_unsafe_fn` lint, which checks whether the unsafe code
+  in an `unsafe fn` is wrapped in a `unsafe` block.][79208] This lint
+  is allowed by default, and may become a warning or hard error in a
+  future edition.
+- [You can now cast mutable references to arrays to a pointer of the same type as
+  the element.][81479]
+
+Compiler
+--------
+- [Upgraded the default LLVM to LLVM 12.][81451]
+
+Added tier 3\* support for the following targets.
+
+- [`s390x-unknown-linux-musl`][82166]
+- [`riscv32gc-unknown-linux-musl` & `riscv64gc-unknown-linux-musl`][82202]
+- [`powerpc-unknown-openbsd`][82733]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+- [`OsString` now implements `Extend` and `FromIterator`.][82121]
+- [`cmp::Reverse` now has `#[repr(transparent)]` representation.][81879]
+- [`Arc<impl Error>` now implements `error::Error`.][80553]
+- [All integer division and remainder operations are now `const`.][80962]
+
+Stabilised APIs
+-------------
+- [`Arguments::as_str`]
+- [`char::MAX`]
+- [`char::REPLACEMENT_CHARACTER`]
+- [`char::UNICODE_VERSION`]
+- [`char::decode_utf16`]
+- [`char::from_digit`]
+- [`char::from_u32_unchecked`]
+- [`char::from_u32`]
+- [`slice::partition_point`]
+- [`str::rsplit_once`]
+- [`str::split_once`]
+
+The following previously stable APIs are now `const`.
+
+- [`char::len_utf8`]
+- [`char::len_utf16`]
+- [`char::to_ascii_uppercase`]
+- [`char::to_ascii_lowercase`]
+- [`char::eq_ignore_ascii_case`]
+- [`u8::to_ascii_uppercase`]
+- [`u8::to_ascii_lowercase`]
+- [`u8::eq_ignore_ascii_case`]
+
+Rustdoc
+-------
+- [Rustdoc lints are now treated as a tool lint, meaning that
+  lints are now prefixed with `rustdoc::` (e.g. `#[warn(rustdoc::non_autolinks)]`).][80527]
+  Using the old style is still allowed, and will become a warning in
+  a future release.
+- [Rustdoc now supports argument files.][82261]
+- [Rustdoc now generates smart punctuation for documentation.][79423]
+- [You can now use "task lists" in Rustdoc Markdown.][81766] E.g.
+  ```markdown
+  - [x] Complete
+  - [ ] Todo
+  ```
+
+Misc
+----
+- [You can now pass multiple filters to tests.][81356] E.g.
+  `cargo test -- foo bar` will run all tests that match `foo` and `bar`.
+- [Rustup now distributes PDB symbols for the `std` library on Windows,
+  allowing you to see `std` symbols when debugging.][82218]
+
+Internal Only
+-------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc and
+related tools.
+
+- [Check the result cache before the DepGraph when ensuring queries][81855]
+- [Try fast_reject::simplify_type in coherence before doing full check][81744]
+- [Only store a LocalDefId in some HIR nodes][81611]
+- [Store HIR attributes in a side table][79519]
+
+Compatibility Notes
+-------------------
+- [Cargo build scripts are now forbidden from setting `RUSTC_BOOTSTRAP`.][cargo/9181]
+- [Removed support for the `x86_64-rumprun-netbsd` target.][82594]
+- [Deprecated the `x86_64-sun-solaris` target in favor of `x86_64-pc-solaris`.][82216]
+- [Rustdoc now only accepts `,`, ` `, and `\t` as delimiters for specifying
+  languages in code blocks.][78429]
+- [Rustc now catches more cases of `pub_use_of_private_extern_crate`][80763]
+- [Changes in how proc macros handle whitespace may lead to panics when used
+  with older `proc-macro-hack` versions. A `cargo update` should be sufficient to fix this in all cases.][84136]
+
+[84136]: https://github.com/rust-lang/rust/issues/84136
+[80763]: https://github.com/rust-lang/rust/pull/80763
+[82166]: https://github.com/rust-lang/rust/pull/82166
+[82121]: https://github.com/rust-lang/rust/pull/82121
+[81879]: https://github.com/rust-lang/rust/pull/81879
+[82261]: https://github.com/rust-lang/rust/pull/82261
+[82218]: https://github.com/rust-lang/rust/pull/82218
+[82216]: https://github.com/rust-lang/rust/pull/82216
+[82202]: https://github.com/rust-lang/rust/pull/82202
+[81855]: https://github.com/rust-lang/rust/pull/81855
+[81766]: https://github.com/rust-lang/rust/pull/81766
+[81744]: https://github.com/rust-lang/rust/pull/81744
+[81611]: https://github.com/rust-lang/rust/pull/81611
+[81479]: https://github.com/rust-lang/rust/pull/81479
+[81451]: https://github.com/rust-lang/rust/pull/81451
+[81356]: https://github.com/rust-lang/rust/pull/81356
+[80962]: https://github.com/rust-lang/rust/pull/80962
+[80553]: https://github.com/rust-lang/rust/pull/80553
+[80527]: https://github.com/rust-lang/rust/pull/80527
+[79519]: https://github.com/rust-lang/rust/pull/79519
+[79423]: https://github.com/rust-lang/rust/pull/79423
+[79208]: https://github.com/rust-lang/rust/pull/79208
+[78429]: https://github.com/rust-lang/rust/pull/78429
+[82733]: https://github.com/rust-lang/rust/pull/82733
+[82594]: https://github.com/rust-lang/rust/pull/82594
+[cargo/9181]: https://github.com/rust-lang/cargo/pull/9181
+[`char::MAX`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.MAX
+[`char::REPLACEMENT_CHARACTER`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.REPLACEMENT_CHARACTER
+[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.UNICODE_VERSION
+[`char::decode_utf16`]: https://doc.rust-lang.org/std/primitive.char.html#method.decode_utf16
+[`char::from_u32`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32
+[`char::from_u32_unchecked`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32_unchecked
+[`char::from_digit`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_digit
+[`Peekable::next_if`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if
+[`Peekable::next_if_eq`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_eq
+[`Arguments::as_str`]: https://doc.rust-lang.org/stable/std/fmt/struct.Arguments.html#method.as_str
+[`str::split_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_once
+[`str::rsplit_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.rsplit_once
+[`slice::partition_point`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.partition_point
+[`char::len_utf8`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf8
+[`char::len_utf16`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf16
+[`char::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_uppercase
+[`char::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_lowercase
+[`char::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.eq_ignore_ascii_case
+[`u8::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_uppercase
+[`u8::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_lowercase
+[`u8::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.eq_ignore_ascii_case
+
 Version 1.51.0 (2021-03-25)
 ============================
 
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..32320130b67 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -46,7 +46,7 @@ use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_ID};
@@ -58,6 +58,7 @@ use rustc_session::lint::builtin::{BARE_TRAIT_OBJECTS, MISSING_ABI};
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
+use rustc_span::edition::Edition;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -165,7 +166,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 +322,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 +595,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 +616,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 +869,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 +1075,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 +1196,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 +1812,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())
@@ -2736,13 +2731,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             .map(|snippet| snippet.starts_with("#["))
             .unwrap_or(true);
         if !is_macro_callsite {
-            self.resolver.lint_buffer().buffer_lint_with_diagnostic(
-                BARE_TRAIT_OBJECTS,
-                id,
-                span,
-                "trait objects without an explicit `dyn` are deprecated",
-                BuiltinLintDiagnostics::BareTraitObject(span, is_global),
-            )
+            if span.edition() < Edition::Edition2021 {
+                self.resolver.lint_buffer().buffer_lint_with_diagnostic(
+                    BARE_TRAIT_OBJECTS,
+                    id,
+                    span,
+                    "trait objects without an explicit `dyn` are deprecated",
+                    BuiltinLintDiagnostics::BareTraitObject(span, is_global),
+                )
+            } else {
+                let msg = "trait objects must include the `dyn` keyword";
+                let label = "add `dyn` keyword before this trait";
+                let mut err = struct_span_err!(self.sess, span, E0782, "{}", msg,);
+                err.span_suggestion_verbose(
+                    span.shrink_to_lo(),
+                    label,
+                    String::from("dyn "),
+                    Applicability::MachineApplicable,
+                );
+                err.emit();
+            }
         }
     }
 
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index da516f5cb41..dc3383dae84 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -326,6 +326,45 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 );
             }
         }
+
+        // Check for unstable modifiers on `#[link(..)]` attribute
+        if self.sess.check_name(attr, sym::link) {
+            for nested_meta in attr.meta_item_list().unwrap_or_default() {
+                if nested_meta.has_name(sym::modifiers) {
+                    gate_feature_post!(
+                        self,
+                        native_link_modifiers,
+                        nested_meta.span(),
+                        "native link modifiers are experimental"
+                    );
+
+                    if let Some(modifiers) = nested_meta.value_str() {
+                        for modifier in modifiers.as_str().split(',') {
+                            if let Some(modifier) = modifier.strip_prefix(&['+', '-'][..]) {
+                                macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
+                                    $(if modifier == $name {
+                                        let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable");
+                                        gate_feature_post!(
+                                            self,
+                                            $feature,
+                                            nested_meta.name_value_literal_span().unwrap(),
+                                            msg
+                                        );
+                                    })*
+                                }}
+
+                                gate_modifier!(
+                                    "bundle" => native_link_modifiers_bundle
+                                    "verbatim" => native_link_modifiers_verbatim
+                                    "whole-archive" => native_link_modifiers_whole_archive
+                                    "as-needed" => native_link_modifiers_as_needed
+                                );
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
 
     fn visit_item(&mut self, i: &'a ast::Item) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 789d2c296e2..fdcb68cf421 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -366,10 +366,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
     }
 
-    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
-        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
-    }
-
     fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
     }
@@ -1675,32 +1671,24 @@ impl<'a> State<'a> {
         }
     }
 
-    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
         self.ibox(INDENT_UNIT);
         self.s.word("[");
-        self.print_inner_attributes_inline(attrs);
         self.commasep_exprs(Inconsistent, exprs);
         self.s.word("]");
         self.end();
     }
 
-    fn print_expr_anon_const(&mut self, expr: &ast::AnonConst, attrs: &[ast::Attribute]) {
+    fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
         self.ibox(INDENT_UNIT);
         self.s.word("const");
-        self.print_inner_attributes_inline(attrs);
         self.print_expr(&expr.value);
         self.end();
     }
 
-    fn print_expr_repeat(
-        &mut self,
-        element: &ast::Expr,
-        count: &ast::AnonConst,
-        attrs: &[ast::Attribute],
-    ) {
+    fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
         self.ibox(INDENT_UNIT);
         self.s.word("[");
-        self.print_inner_attributes_inline(attrs);
         self.print_expr(element);
         self.word_space(";");
         self.print_expr(&count.value);
@@ -1713,11 +1701,9 @@ impl<'a> State<'a> {
         path: &ast::Path,
         fields: &[ast::ExprField],
         rest: &ast::StructRest,
-        attrs: &[ast::Attribute],
     ) {
         self.print_path(path, true, 0);
         self.s.word("{");
-        self.print_inner_attributes_inline(attrs);
         self.commasep_cmnt(
             Consistent,
             fields,
@@ -1752,9 +1738,8 @@ impl<'a> State<'a> {
         self.s.word("}");
     }
 
-    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
         self.popen();
-        self.print_inner_attributes_inline(attrs);
         self.commasep_exprs(Inconsistent, exprs);
         if exprs.len() == 1 {
             self.s.word(",");
@@ -1865,19 +1850,19 @@ impl<'a> State<'a> {
                 self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
             }
             ast::ExprKind::Array(ref exprs) => {
-                self.print_expr_vec(&exprs[..], attrs);
+                self.print_expr_vec(exprs);
             }
             ast::ExprKind::ConstBlock(ref anon_const) => {
-                self.print_expr_anon_const(anon_const, attrs);
+                self.print_expr_anon_const(anon_const);
             }
             ast::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(element, count, attrs);
+                self.print_expr_repeat(element, count);
             }
             ast::ExprKind::Struct(ref se) => {
-                self.print_expr_struct(&se.path, &se.fields, &se.rest, attrs);
+                self.print_expr_struct(&se.path, &se.fields, &se.rest);
             }
             ast::ExprKind::Tup(ref exprs) => {
-                self.print_expr_tup(&exprs[..], attrs);
+                self.print_expr_tup(exprs);
             }
             ast::ExprKind::Call(ref func, ref args) => {
                 self.print_expr_call(func, &args[..]);
@@ -1955,7 +1940,6 @@ impl<'a> State<'a> {
                 self.print_expr_as_cond(expr);
                 self.s.space();
                 self.bopen();
-                self.print_inner_attributes_no_trailing_hardbreak(attrs);
                 for arm in arms {
                     self.print_arm(arm);
                 }
@@ -2253,7 +2237,6 @@ impl<'a> State<'a> {
             ast::ExprKind::MacCall(ref m) => self.print_mac(m),
             ast::ExprKind::Paren(ref e) => {
                 self.popen();
-                self.print_inner_attributes_inline(attrs);
                 self.print_expr(e);
                 self.pclose();
             }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 5a4e7fd9d07..54ab88dc3ff 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -15,20 +15,12 @@ pub fn expand_deriving_eq(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
+    let span = cx.with_def_site_ctxt(span);
     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(no_coverage_feature),
-        cx.attribute(no_coverage),
-        cx.attribute(doc),
-    ];
+    let no_coverage = cx.meta_word(span, sym::no_coverage);
+    let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index 7583fc42407..fc0823302e0 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -85,8 +85,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
         ));
     }
 
-    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol) {
-        let location = find_library(name, &self.lib_search_paths, self.sess);
+    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) {
+        let location = find_library(name, verbatim, &self.lib_search_paths, self.sess);
         self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| {
             panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
         });
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 4e7213853b0..261affe2c42 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -100,8 +100,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
 
     /// Adds all of the contents of a native library to this archive. This will
     /// search in the relevant locations for a library named `name`.
-    fn add_native_library(&mut self, name: Symbol) {
-        let location = find_library(name, &self.config.lib_search_paths, self.config.sess);
+    fn add_native_library(&mut self, name: Symbol, verbatim: bool) {
+        let location =
+            find_library(name, verbatim, &self.config.lib_search_paths, self.config.sess);
         self.add_archive(&location, |_| false).unwrap_or_else(|e| {
             self.config.sess.fatal(&format!(
                 "failed to add native library {}: {}",
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 1faaa7e86f6..30f125ca3be 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -8,7 +8,6 @@ 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;
 
@@ -249,7 +248,7 @@ fn save_function_record(
 ///
 /// We can find the unused functions (including generic functions) by the set difference of all MIR
 /// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query
-/// `collect_and_partition_mono_items`).
+/// `codegened_and_inlined_items`).
 ///
 /// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and
 /// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`)
@@ -281,11 +280,8 @@ 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
+        // Make sure the non-codegenned (unused) function has at least one MIR
+        // `Coverage` statement with a code region, and return its file name.
         if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
             let def_ids =
                 unused_def_ids_by_file.entry(*non_codegenned_file_name).or_insert_with(Vec::new);
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/metadata.rs b/compiler/rustc_codegen_llvm/src/metadata.rs
index b007df57306..decc1e1f700 100644
--- a/compiler/rustc_codegen_llvm/src/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/metadata.rs
@@ -66,7 +66,7 @@ fn search_meta_section<'a>(
             let mut name_buf = None;
             let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
             let name = name_buf.map_or_else(
-                String::new, // We got a NULL ptr, ignore `name_len`.
+                String::new, // We got a null ptr, ignore `name_len`.
                 |buf| {
                     String::from_utf8(
                         slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index c477ac6462a..c197d48d4ea 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -4,11 +4,19 @@ use rustc_span::symbol::Symbol;
 use std::io;
 use std::path::{Path, PathBuf};
 
-pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> PathBuf {
+pub fn find_library(
+    name: Symbol,
+    verbatim: bool,
+    search_paths: &[PathBuf],
+    sess: &Session,
+) -> PathBuf {
     // On Windows, static libraries sometimes show up as libfoo.a and other
     // times show up as foo.lib
-    let oslibname =
-        format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix);
+    let oslibname = if verbatim {
+        name.to_string()
+    } else {
+        format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix)
+    };
     let unixlibname = format!("lib{}.a", name);
 
     for path in search_paths {
@@ -45,7 +53,7 @@ pub trait ArchiveBuilder<'a> {
         lto: bool,
         skip_objects: bool,
     ) -> io::Result<()>;
-    fn add_native_library(&mut self, name: Symbol);
+    fn add_native_library(&mut self, name: Symbol, verbatim: bool);
     fn update_symbols(&mut self);
 
     fn build(self);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ea75943d6f3..59f66c55572 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -329,15 +329,15 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
     // metadata of the rlib we're generating somehow.
     for lib in codegen_results.crate_info.used_libraries.iter() {
         match lib.kind {
-            NativeLibKind::StaticBundle => {}
-            NativeLibKind::StaticNoBundle
-            | NativeLibKind::Dylib
-            | NativeLibKind::Framework
+            NativeLibKind::Static { bundle: None | Some(true), .. } => {}
+            NativeLibKind::Static { bundle: Some(false), .. }
+            | NativeLibKind::Dylib { .. }
+            | NativeLibKind::Framework { .. }
             | NativeLibKind::RawDylib
             | NativeLibKind::Unspecified => continue,
         }
         if let Some(name) = lib.name {
-            ab.add_native_library(name);
+            ab.add_native_library(name, lib.verbatim.unwrap_or(false));
         }
     }
 
@@ -430,9 +430,10 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
         // Clearly this is not sufficient for a general purpose feature, and
         // we'd want to read from the library's metadata to determine which
         // object files come from where and selectively skip them.
-        let skip_object_files = native_libs
-            .iter()
-            .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
+        let skip_object_files = native_libs.iter().any(|lib| {
+            matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+                && !relevant_lib(sess, lib)
+        });
         ab.add_rlib(
             path,
             &name.as_str(),
@@ -931,7 +932,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
         let path = find_sanitizer_runtime(&sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
         linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
-        linker.link_dylib(Symbol::intern(&filename));
+        linker.link_dylib(Symbol::intern(&filename), false, true);
     } else {
         let filename = format!("librustc{}_rt.{}.a", channel, name);
         let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
@@ -1080,21 +1081,25 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
         .filter_map(|lib| {
             let name = lib.name?;
             match lib.kind {
-                NativeLibKind::StaticNoBundle
-                | NativeLibKind::Dylib
+                NativeLibKind::Static { bundle: Some(false), .. }
+                | NativeLibKind::Dylib { .. }
                 | NativeLibKind::Unspecified => {
+                    let verbatim = lib.verbatim.unwrap_or(false);
                     if sess.target.is_like_msvc {
-                        Some(format!("{}.lib", name))
+                        Some(format!("{}{}", name, if verbatim { "" } else { ".lib" }))
+                    } else if sess.target.linker_is_gnu {
+                        Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
                     } else {
                         Some(format!("-l{}", name))
                     }
                 }
-                NativeLibKind::Framework => {
+                NativeLibKind::Framework { .. } => {
                     // ld-only syntax, since there are no frameworks in MSVC
                     Some(format!("-framework {}", name))
                 }
                 // These are included, no need to print them
-                NativeLibKind::StaticBundle | NativeLibKind::RawDylib => None,
+                NativeLibKind::Static { bundle: None | Some(true), .. }
+                | NativeLibKind::RawDylib => None,
             }
         })
         .collect();
@@ -1803,16 +1808,29 @@ fn add_local_native_libraries(
         codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l));
 
     let search_path = archive_search_paths(sess);
+    let mut last = (NativeLibKind::Unspecified, None);
     for lib in relevant_libs {
+        // Skip if this library is the same as the last.
+        last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
         let name = match lib.name {
             Some(l) => l,
             None => continue,
         };
+        let verbatim = lib.verbatim.unwrap_or(false);
         match lib.kind {
-            NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
-            NativeLibKind::Framework => cmd.link_framework(name),
-            NativeLibKind::StaticNoBundle => cmd.link_staticlib(name),
-            NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path),
+            NativeLibKind::Dylib { as_needed } => {
+                cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+            }
+            NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
+            NativeLibKind::Framework { as_needed } => {
+                cmd.link_framework(name, as_needed.unwrap_or(true))
+            }
+            NativeLibKind::Static { bundle: None | Some(true), .. }
+            | NativeLibKind::Static { whole_archive: Some(true), .. } => {
+                cmd.link_whole_staticlib(name, verbatim, &search_path);
+            }
+            NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim),
             NativeLibKind::RawDylib => {
                 // FIXME(#58713): Proper handling for raw dylibs.
                 bug!("raw_dylib feature not yet implemented");
@@ -1996,9 +2014,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
         // there's a static library that's not relevant we skip all object
         // files.
         let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
-        let skip_native = native_libs
-            .iter()
-            .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
+        let skip_native = native_libs.iter().any(|lib| {
+            matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+                && !relevant_lib(sess, lib)
+        });
 
         if (!are_upstream_rust_objects_already_included(sess)
             || ignored_for_lto(sess, &codegen_results.crate_info, cnum))
@@ -2127,8 +2146,12 @@ fn add_upstream_native_libraries(
         .expect("failed to find crate type in dependency format list");
 
     let crates = &codegen_results.crate_info.used_crates_static;
+    let mut last = (NativeLibKind::Unspecified, None);
     for &(cnum, _) in crates {
         for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
+            // Skip if this library is the same as the last.
+            last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
             let name = match lib.name {
                 Some(l) => l,
                 None => continue,
@@ -2136,22 +2159,28 @@ fn add_upstream_native_libraries(
             if !relevant_lib(sess, &lib) {
                 continue;
             }
+            let verbatim = lib.verbatim.unwrap_or(false);
             match lib.kind {
-                NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
-                NativeLibKind::Framework => cmd.link_framework(name),
-                NativeLibKind::StaticNoBundle => {
+                NativeLibKind::Dylib { as_needed } => {
+                    cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+                }
+                NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
+                NativeLibKind::Framework { as_needed } => {
+                    cmd.link_framework(name, as_needed.unwrap_or(true))
+                }
+                NativeLibKind::Static { bundle: Some(false), .. } => {
                     // Link "static-nobundle" native libs only if the crate they originate from
                     // is being linked statically to the current crate.  If it's linked dynamically
                     // or is an rlib already included via some other dylib crate, the symbols from
                     // native libs will have already been included in that dylib.
                     if data[cnum.as_usize() - 1] == Linkage::Static {
-                        cmd.link_staticlib(name)
+                        cmd.link_staticlib(name, verbatim)
                     }
                 }
                 // ignore statically included native libraries here as we've
                 // already included them when we included the rust library
                 // previously
-                NativeLibKind::StaticBundle => {}
+                NativeLibKind::Static { bundle: None | Some(true), .. } => {}
                 NativeLibKind::RawDylib => {
                     // FIXME(#58713): Proper handling for raw dylibs.
                     bug!("raw_dylib feature not yet implemented");
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 77d8ab49ff2..401d379b0d1 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -103,18 +103,19 @@ impl LinkerInfo {
 pub trait Linker {
     fn cmd(&mut self) -> &mut Command;
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
-    fn link_dylib(&mut self, lib: Symbol);
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool);
     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
-    fn link_framework(&mut self, framework: Symbol);
-    fn link_staticlib(&mut self, lib: Symbol);
+    fn link_framework(&mut self, framework: Symbol, as_needed: bool);
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool);
     fn link_rlib(&mut self, lib: &Path);
     fn link_whole_rlib(&mut self, lib: &Path);
-    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]);
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]);
     fn include_path(&mut self, path: &Path);
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
     fn add_object(&mut self, path: &Path);
     fn gc_sections(&mut self, keep_metadata: bool);
+    fn no_gc_sections(&mut self);
     fn full_relro(&mut self);
     fn partial_relro(&mut self);
     fn no_relro(&mut self);
@@ -338,13 +339,32 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // FIXME(81490): ld64 doesn't support these flags but macOS 11
+                // has -needed-l{} / -needed_library {}
+                // but we have no way to detect that here.
+                self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+            } else if self.sess.target.linker_is_gnu {
+                self.linker_arg("--no-as-needed");
+            } else {
+                self.sess.warn("`as-needed` modifier not supported for current linker");
+            }
+        }
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // See above FIXME comment
+            } else if self.sess.target.linker_is_gnu {
+                self.linker_arg("--as-needed");
+            }
+        }
     }
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
         self.hint_static();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
     }
     fn link_rlib(&mut self, lib: &Path) {
         self.hint_static();
@@ -378,8 +398,14 @@ impl<'a> Linker for GccLinker<'a> {
         self.cmd.arg(format!("-l{}", lib));
     }
 
-    fn link_framework(&mut self, framework: Symbol) {
+    fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
         self.hint_dynamic();
+        if !as_needed {
+            // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
+            // flag but we have no way to detect that here.
+            // self.cmd.arg("-needed_framework").sym_arg(framework);
+            self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+        }
         self.cmd.arg("-framework").sym_arg(framework);
     }
 
@@ -389,17 +415,21 @@ impl<'a> Linker for GccLinker<'a> {
     // don't otherwise explicitly reference them. This can occur for
     // libraries which are just providing bindings, libraries with generic
     // functions, etc.
-    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) {
         self.hint_static();
         let target = &self.sess.target;
         if !target.is_like_osx {
-            self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
+            self.linker_arg("--whole-archive").cmd.arg(format!(
+                "-l{}{}",
+                if verbatim { ":" } else { "" },
+                lib
+            ));
             self.linker_arg("--no-whole-archive");
         } else {
             // -force_load is the macOS equivalent of --whole-archive, but it
             // involves passing the full path to the library to link.
             self.linker_arg("-force_load");
-            let lib = archive::find_library(lib, search_path, &self.sess);
+            let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
             self.linker_arg(&lib);
         }
     }
@@ -432,8 +462,6 @@ impl<'a> Linker for GccLinker<'a> {
         // insert it here.
         if self.sess.target.is_like_osx {
             self.linker_arg("-dead_strip");
-        } else if self.sess.target.is_like_solaris {
-            self.linker_arg("-zignore");
 
         // If we're building a dylib, we don't use --gc-sections because LLVM
         // has already done the best it can do, and we also don't want to
@@ -445,6 +473,16 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
+    fn no_gc_sections(&mut self) {
+        if self.sess.target.is_like_osx {
+            self.linker_arg("-no_dead_strip");
+        } else if self.sess.target.is_like_solaris {
+            self.linker_arg("-zrecord");
+        } else {
+            self.linker_arg("--no-gc-sections");
+        }
+    }
+
     fn optimize(&mut self) {
         if !self.sess.target.linker_is_gnu {
             return;
@@ -655,6 +693,10 @@ impl<'a> Linker for GccLinker<'a> {
     fn add_as_needed(&mut self) {
         if self.sess.target.linker_is_gnu {
             self.linker_arg("--as-needed");
+        } else if self.sess.target.is_like_solaris {
+            // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
+            self.linker_arg("-z");
+            self.linker_arg("ignore");
         }
     }
 }
@@ -708,8 +750,12 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
-        self.cmd.arg(&format!("{}.lib", lib));
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("/OPT:NOREF,NOICF");
+    }
+
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
+        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
@@ -723,8 +769,8 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
-        self.cmd.arg(&format!("{}.lib", lib));
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
+        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
     fn full_relro(&mut self) {
@@ -762,13 +808,13 @@ impl<'a> Linker for MsvcLinker<'a> {
     fn framework_path(&mut self, _path: &Path) {
         bug!("frameworks are not supported on windows")
     }
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         bug!("frameworks are not supported on windows")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
-        self.link_staticlib(lib);
-        self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
+        self.link_staticlib(lib, verbatim);
+        self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
     fn link_whole_rlib(&mut self, path: &Path) {
         self.link_rlib(path);
@@ -917,7 +963,7 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.arg("-L").arg(path);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -929,14 +975,14 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.arg(path);
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
         // Emscripten always links statically
-        self.link_staticlib(lib);
+        self.link_staticlib(lib, verbatim);
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
         // not supported?
-        self.link_staticlib(lib);
+        self.link_staticlib(lib, verbatim);
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
@@ -945,7 +991,7 @@ impl<'a> Linker for EmLinker<'a> {
     }
 
     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
-        self.link_dylib(lib);
+        self.link_dylib(lib, false, true);
     }
 
     fn link_rlib(&mut self, lib: &Path) {
@@ -968,7 +1014,7 @@ impl<'a> Linker for EmLinker<'a> {
         bug!("frameworks are not supported on Emscripten")
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         bug!("frameworks are not supported on Emscripten")
     }
 
@@ -976,6 +1022,10 @@ impl<'a> Linker for EmLinker<'a> {
         // noop
     }
 
+    fn no_gc_sections(&mut self) {
+        // noop
+    }
+
     fn optimize(&mut self) {
         // Emscripten performs own optimizations
         self.cmd.arg(match self.sess.opts.optimize {
@@ -1119,11 +1169,11 @@ impl<'a> Linker for WasmLd<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -1157,11 +1207,11 @@ impl<'a> Linker for WasmLd<'a> {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -1173,6 +1223,10 @@ impl<'a> Linker for WasmLd<'a> {
         self.cmd.arg("--gc-sections");
     }
 
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("--no-gc-sections");
+    }
+
     fn optimize(&mut self) {
         self.cmd.arg(match self.sess.opts.optimize {
             OptLevel::No => "-O0",
@@ -1327,7 +1381,7 @@ impl<'a> Linker for PtxLinker<'a> {
         });
     }
 
-    fn link_dylib(&mut self, _lib: Symbol) {
+    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
         panic!("external dylibs not supported")
     }
 
@@ -1335,11 +1389,11 @@ impl<'a> Linker for PtxLinker<'a> {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib(&mut self, _lib: Symbol) {
+    fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
         panic!("staticlibs not supported")
     }
 
-    fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
         panic!("staticlibs not supported")
     }
 
@@ -1347,7 +1401,7 @@ impl<'a> Linker for PtxLinker<'a> {
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
@@ -1359,6 +1413,8 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn gc_sections(&mut self, _keep_metadata: bool) {}
 
+    fn no_gc_sections(&mut self) {}
+
     fn pgo_gen(&mut self) {}
 
     fn no_crt_objects(&mut self) {}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index f0f45b067b3..1b53b551901 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -114,11 +114,12 @@ pub struct NativeLib {
     pub kind: NativeLibKind,
     pub name: Option<Symbol>,
     pub cfg: Option<ast::MetaItem>,
+    pub verbatim: Option<bool>,
 }
 
 impl From<&cstore::NativeLib> for NativeLib {
     fn from(lib: &cstore::NativeLib) -> Self {
-        NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() }
+        NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim }
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index a5b2df1da5d..29d685ab530 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -336,12 +336,13 @@ impl<O: ForestObligation> ObligationForest<O> {
 
     // Returns Err(()) if we already know this obligation failed.
     fn register_obligation_at(&mut self, obligation: O, parent: Option<usize>) -> Result<(), ()> {
-        if self.done_cache.contains(&obligation.as_cache_key()) {
+        let cache_key = obligation.as_cache_key();
+        if self.done_cache.contains(&cache_key) {
             debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation);
             return Ok(());
         }
 
-        match self.active_cache.entry(obligation.as_cache_key()) {
+        match self.active_cache.entry(cache_key.clone()) {
             Entry::Occupied(o) => {
                 let node = &mut self.nodes[*o.get()];
                 if let Some(parent_index) = parent {
@@ -365,7 +366,7 @@ impl<O: ForestObligation> ObligationForest<O> {
                     && self
                         .error_cache
                         .get(&obligation_tree_id)
-                        .map(|errors| errors.contains(&obligation.as_cache_key()))
+                        .map(|errors| errors.contains(&cache_key))
                         .unwrap_or(false);
 
                 if already_failed {
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 41a1fa488d3..c343809179b 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -470,6 +470,8 @@ E0778: include_str!("./error_codes/E0778.md"),
 E0779: include_str!("./error_codes/E0779.md"),
 E0780: include_str!("./error_codes/E0780.md"),
 E0781: include_str!("./error_codes/E0781.md"),
+E0782: include_str!("./error_codes/E0782.md"),
+E0783: include_str!("./error_codes/E0783.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/compiler/rustc_error_codes/src/error_codes/E0782.md b/compiler/rustc_error_codes/src/error_codes/E0782.md
new file mode 100644
index 00000000000..0f3253c050e
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0782.md
@@ -0,0 +1,26 @@
+Trait objects must include the `dyn` keyword.
+
+Erroneous code example:
+
+```edition2021,compile_fail,E0782
+trait Foo {}
+fn test(arg: Box<Foo>) {} // error!
+```
+
+Trait objects are a way to call methods on types that are not known until
+runtime but conform to some trait.
+
+Trait objects should be formed with `Box<dyn Foo>`, but in the code above
+`dyn` is left off.
+
+This makes it harder to see that `arg` is a trait object and not a
+simply a heap allocated type called `Foo`.
+
+To fix this issue, add `dyn` before the trait name.
+
+```edition2021
+trait Foo {}
+fn test(arg: Box<dyn Foo>) {} // ok!
+```
+
+This used to be allowed before edition 2021, but is now an error.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0783.md b/compiler/rustc_error_codes/src/error_codes/E0783.md
new file mode 100644
index 00000000000..73981e59e0d
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0783.md
@@ -0,0 +1,22 @@
+The range pattern `...` is no longer allowed.
+
+Erroneous code example:
+
+```edition2021,compile_fail,E0783
+match 2u8 {
+    0...9 => println!("Got a number less than 10"), // error!
+    _ => println!("Got a number 10 or more"),
+}
+```
+
+Older Rust code using previous editions allowed `...` to stand for exclusive
+ranges which are now signified using `..=`.
+
+To make this code compile replace the `...` with `..=`.
+
+```edition2021
+match 2u8 {
+    0..=9 => println!("Got a number less than 10"), // ok!
+    _ => println!("Got a number 10 or more"),
+}
+```
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index f1a31f0d4f5..6aee769298b 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -294,6 +294,7 @@ impl error::Error for ExplicitBug {}
 
 pub use diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic};
 pub use diagnostic_builder::DiagnosticBuilder;
+use std::backtrace::Backtrace;
 
 /// A handler deals with errors and other compiler output.
 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
@@ -317,7 +318,7 @@ struct HandlerInner {
     deduplicated_err_count: usize,
     emitter: Box<dyn Emitter + sync::Send>,
     delayed_span_bugs: Vec<Diagnostic>,
-    delayed_good_path_bugs: Vec<Diagnostic>,
+    delayed_good_path_bugs: Vec<DelayedDiagnostic>,
 
     /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
     /// emitting the same diagnostic with extended help (`--teach`) twice, which
@@ -388,7 +389,7 @@ impl Drop for HandlerInner {
         if !self.has_any_message() {
             let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
             self.flush_delayed(
-                bugs,
+                bugs.into_iter().map(DelayedDiagnostic::decorate).collect(),
                 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
             );
         }
@@ -968,12 +969,12 @@ impl HandlerInner {
     }
 
     fn delay_good_path_bug(&mut self, msg: &str) {
-        let mut diagnostic = Diagnostic::new(Level::Bug, msg);
+        let diagnostic = Diagnostic::new(Level::Bug, msg);
         if self.flags.report_delayed_bugs {
             self.emit_diagnostic(&diagnostic);
         }
-        diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture()));
-        self.delayed_good_path_bugs.push(diagnostic);
+        let backtrace = std::backtrace::Backtrace::force_capture();
+        self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
     }
 
     fn failure(&mut self, msg: &str) {
@@ -1042,6 +1043,22 @@ impl HandlerInner {
     }
 }
 
+struct DelayedDiagnostic {
+    inner: Diagnostic,
+    note: Backtrace,
+}
+
+impl DelayedDiagnostic {
+    fn with_backtrace(diagnostic: Diagnostic, backtrace: Backtrace) -> Self {
+        DelayedDiagnostic { inner: diagnostic, note: backtrace }
+    }
+
+    fn decorate(mut self) -> Diagnostic {
+        self.inner.note(&format!("delayed at {}", self.note));
+        self.inner
+    }
+}
+
 #[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)]
 pub enum Level {
     Bug,
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index c5ce0baaa8f..4d777049f0d 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -36,8 +36,8 @@ crate struct ParsedExternalMod {
 pub enum ModError<'a> {
     CircularInclusion(Vec<PathBuf>),
     ModInBlock(Option<Ident>),
-    FileNotFound(Ident, PathBuf),
-    MultipleCandidates(Ident, String, String),
+    FileNotFound(Ident, PathBuf, PathBuf),
+    MultipleCandidates(Ident, PathBuf, PathBuf),
     ParserError(DiagnosticBuilder<'a>),
 }
 
@@ -219,10 +219,8 @@ pub fn default_submod_path<'a>(
             file_path: secondary_path,
             dir_ownership: DirOwnership::Owned { relative: None },
         }),
-        (false, false) => Err(ModError::FileNotFound(ident, default_path)),
-        (true, true) => {
-            Err(ModError::MultipleCandidates(ident, default_path_str, secondary_path_str))
-        }
+        (false, false) => Err(ModError::FileNotFound(ident, default_path, secondary_path)),
+        (true, true) => Err(ModError::MultipleCandidates(ident, default_path, secondary_path)),
     }
 }
 
@@ -249,7 +247,7 @@ impl ModError<'_> {
                 }
                 err
             }
-            ModError::FileNotFound(ident, default_path) => {
+            ModError::FileNotFound(ident, default_path, secondary_path) => {
                 let mut err = struct_span_err!(
                     diag,
                     span,
@@ -258,21 +256,22 @@ impl ModError<'_> {
                     ident,
                 );
                 err.help(&format!(
-                    "to create the module `{}`, create file \"{}\"",
+                    "to create the module `{}`, create file \"{}\" or \"{}\"",
                     ident,
                     default_path.display(),
+                    secondary_path.display(),
                 ));
                 err
             }
-            ModError::MultipleCandidates(ident, default_path_short, secondary_path_short) => {
+            ModError::MultipleCandidates(ident, default_path, secondary_path) => {
                 let mut err = struct_span_err!(
                     diag,
                     span,
                     E0761,
-                    "file for module `{}` found at both {} and {}",
+                    "file for module `{}` found at both \"{}\" and \"{}\"",
                     ident,
-                    default_path_short,
-                    secondary_path_short,
+                    default_path.display(),
+                    secondary_path.display(),
                 );
                 err.help("delete or rename one of them to remove the ambiguity");
                 err
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 4ad5f085ad0..f747f854514 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -656,6 +656,21 @@ declare_features! (
     /// Allows using imported `main` function
     (active, imported_main, "1.53.0", Some(28937), None),
 
+    /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
+    (active, native_link_modifiers, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the bundle link modifier
+    (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the verbatim link modifier
+    (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the whole-archive link modifier
+    (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the as-needed link modifier
+    (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -683,6 +698,11 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
     sym::const_generics_defaults,
     sym::inherent_associated_types,
     sym::type_alias_impl_trait,
+    sym::native_link_modifiers,
+    sym::native_link_modifiers_bundle,
+    sym::native_link_modifiers_verbatim,
+    sym::native_link_modifiers_whole_archive,
+    sym::native_link_modifiers_as_needed,
 ];
 
 /// Some features are not allowed to be used together at the same time, if
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 5474fea9c78..a8719be84c2 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -273,13 +273,7 @@ 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),
-    ),
+    gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)),
 
     // 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_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 0f77de9fb25..647d735fb86 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -87,11 +87,6 @@ impl DefPathTable {
         hash
     }
 
-    /// Used by librustdoc for fake DefIds.
-    pub fn num_def_ids(&self) -> usize {
-        self.index_to_key.len()
-    }
-
     pub fn enumerated_keys_and_path_hashes(
         &self,
     ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index d26ab1939e3..df777502c44 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -355,14 +355,18 @@ where
     Op: Fn(Word, Word) -> Word,
 {
     assert_eq!(out_vec.len(), in_vec.len());
-    let mut changed = false;
+    let mut changed = 0;
     for (out_elem, in_elem) in iter::zip(out_vec, in_vec) {
         let old_val = *out_elem;
         let new_val = op(old_val, *in_elem);
         *out_elem = new_val;
-        changed |= old_val != new_val;
+        // This is essentially equivalent to a != with changed being a bool, but
+        // in practice this code gets auto-vectorized by the compiler for most
+        // operators. Using != here causes us to generate quite poor code as the
+        // compiler tries to go back to a boolean on each loop iteration.
+        changed |= old_val ^ new_val;
     }
-    changed
+    changed != 0
 }
 
 const SPARSE_MAX: usize = 8;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index a91bd9ce2ff..1cafb2fe1a2 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2398,9 +2398,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 self.tcx.associated_item(def_id).ident
             ),
             infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
-            infer::BoundRegionInCoherence(name) => {
-                format!(" for lifetime parameter `{}` in coherence check", name)
-            }
             infer::UpvarRegion(ref upvar_id, _) => {
                 let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
                 format!(" for capture of `{}` by closure", var_name)
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index eaec6b46bcd..f39431f2494 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -453,8 +453,6 @@ pub enum RegionVariableOrigin {
 
     UpvarRegion(ty::UpvarId, Span),
 
-    BoundRegionInCoherence(Symbol),
-
     /// This origin is used for the inference variables that we create
     /// during NLL region processing.
     Nll(NllRegionVariableOrigin),
@@ -1749,7 +1747,6 @@ impl RegionVariableOrigin {
             | EarlyBoundRegion(a, ..)
             | LateBoundRegion(a, ..)
             | UpvarRegion(_, a) => a,
-            BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
             Nll(..) => bug!("NLL variable used with `span`"),
         }
     }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index d8c1a7a2682..4d87bbead41 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -12,7 +12,7 @@ use rustc_session::config::{
 };
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
-use rustc_session::utils::{CanonicalizedPath, NativeLibKind};
+use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use rustc_session::{build_session, getopts, DiagnosticOutput, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
@@ -303,38 +303,122 @@ fn test_native_libs_tracking_hash_different_values() {
     let mut v2 = Options::default();
     let mut v3 = Options::default();
     let mut v4 = Options::default();
+    let mut v5 = Options::default();
 
     // Reference
     v1.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     // Change label
     v2.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("X"), None, NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("X"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     // Change kind
     v3.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::StaticBundle),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     // Change new-name
     v4.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), Some(String::from("X")), NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: Some(String::from("X")),
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
+    ];
+
+    // Change verbatim
+    v5.libs = vec![
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: Some(true),
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     assert_different_hash(&v1, &v2);
     assert_different_hash(&v1, &v3);
     assert_different_hash(&v1, &v4);
+    assert_different_hash(&v1, &v5);
 }
 
 #[test]
@@ -345,21 +429,66 @@ fn test_native_libs_tracking_hash_different_order() {
 
     // Reference
     v1.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     v2.libs = vec![
-        (String::from("b"), None, NativeLibKind::Framework),
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     v3.libs = vec![
-        (String::from("c"), None, NativeLibKind::Unspecified),
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::Framework),
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
     ];
 
     assert_same_hash(&v1, &v2);
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 3965a3dcdfd..e7275374b89 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1660,7 +1660,11 @@ declare_lint! {
     /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
     pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
     Warn,
-    "`...` range patterns are deprecated"
+    "`...` range patterns are deprecated",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+        edition: Some(Edition::Edition2021),
+    };
 }
 
 #[derive(Default)]
@@ -1704,32 +1708,57 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
             let suggestion = "use `..=` for an inclusive range";
             if parenthesise {
                 self.node_id = Some(pat.id);
-                cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
-                    let end = expr_to_string(&end);
-                    let replace = match start {
-                        Some(start) => format!("&({}..={})", expr_to_string(&start), end),
-                        None => format!("&(..={})", end),
-                    };
-                    lint.build(msg)
-                        .span_suggestion(
-                            pat.span,
-                            suggestion,
-                            replace,
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
-                });
+                let end = expr_to_string(&end);
+                let replace = match start {
+                    Some(start) => format!("&({}..={})", expr_to_string(&start), end),
+                    None => format!("&(..={})", end),
+                };
+                if join.edition() >= Edition::Edition2021 {
+                    let mut err =
+                        rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+                    err.span_suggestion(
+                        pat.span,
+                        suggestion,
+                        replace,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                } else {
+                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
+                        lint.build(msg)
+                            .span_suggestion(
+                                pat.span,
+                                suggestion,
+                                replace,
+                                Applicability::MachineApplicable,
+                            )
+                            .emit();
+                    });
+                }
             } else {
-                cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
-                    lint.build(msg)
-                        .span_suggestion_short(
-                            join,
-                            suggestion,
-                            "..=".to_owned(),
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
-                });
+                let replace = "..=".to_owned();
+                if join.edition() >= Edition::Edition2021 {
+                    let mut err =
+                        rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+                    err.span_suggestion_short(
+                        join,
+                        suggestion,
+                        replace,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                } else {
+                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
+                        lint.build(msg)
+                            .span_suggestion_short(
+                                join,
+                                suggestion,
+                                replace,
+                                Applicability::MachineApplicable,
+                            )
+                            .emit();
+                    });
+                }
             };
         }
     }
@@ -2328,7 +2357,7 @@ const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
 
 declare_lint! {
     /// The `invalid_value` lint detects creating a value that is not valid,
-    /// such as a NULL reference.
+    /// such as a null reference.
     ///
     /// ### Example
     ///
@@ -2359,7 +2388,7 @@ declare_lint! {
     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     pub INVALID_VALUE,
     Warn,
-    "an invalid value is being created (such as a NULL reference)"
+    "an invalid value is being created (such as a null reference)"
 }
 
 declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 04e45e2351b..beb4d36597c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1618,7 +1618,11 @@ declare_lint! {
     /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
     pub BARE_TRAIT_OBJECTS,
     Warn,
-    "suggest using `dyn Trait` for trait objects"
+    "suggest using `dyn Trait` for trait objects",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+        edition: Some(Edition::Edition2021),
+    };
 }
 
 declare_lint! {
diff --git a/compiler/rustc_metadata/src/dynamic_lib.rs b/compiler/rustc_metadata/src/dynamic_lib.rs
index bdb53e3f75a..1a900ccbf65 100644
--- a/compiler/rustc_metadata/src/dynamic_lib.rs
+++ b/compiler/rustc_metadata/src/dynamic_lib.rs
@@ -105,7 +105,7 @@ mod dl {
             return Ok(ret.cast());
         }
 
-        // A NULL return from `dlopen` indicates that an error has definitely occurred, so if
+        // A null return from `dlopen` indicates that an error has definitely occurred, so if
         // nothing is in `dlerror`, we are racing with another thread that has stolen our error
         // message. See the explanation on the `dl::error` module for more information.
         dlerror.get().and_then(|()| Err("Unknown error".to_string()))
@@ -117,7 +117,7 @@ mod dl {
     ) -> Result<*mut u8, String> {
         let mut dlerror = error::lock();
 
-        // Unlike `dlopen`, it's possible for `dlsym` to return NULL without overwriting `dlerror`.
+        // Unlike `dlopen`, it's possible for `dlsym` to return null without overwriting `dlerror`.
         // Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale
         // error message by accident.
         dlerror.clear();
@@ -128,7 +128,7 @@ mod dl {
             return Ok(ret.cast());
         }
 
-        // If `dlsym` returns NULL but there is nothing in `dlerror` it means one of two things:
+        // If `dlsym` returns null but there is nothing in `dlerror` it means one of two things:
         // - We tried to load a symbol mapped to address 0. This is not technically an error but is
         //   unlikely to occur in practice and equally unlikely to be handled correctly by calling
         //   code. Therefore we treat it as an error anyway.
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 523e016eeb9..bc342119efb 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -8,8 +8,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
-use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
@@ -56,6 +56,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                 cfg: None,
                 foreign_module: Some(it.def_id.to_def_id()),
                 wasm_import_module: None,
+                verbatim: None,
             };
             let mut kind_specified = false;
 
@@ -67,10 +68,18 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                         None => continue, // skip like historical compilers
                     };
                     lib.kind = match &*kind.as_str() {
-                        "static" => NativeLibKind::StaticBundle,
-                        "static-nobundle" => NativeLibKind::StaticNoBundle,
-                        "dylib" => NativeLibKind::Dylib,
-                        "framework" => NativeLibKind::Framework,
+                        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+                        "static-nobundle" => {
+                            sess.struct_span_warn(
+                                item.span(),
+                                "library kind `static-nobundle` has been superseded by specifying \
+                                modifier `-bundle` with library kind `static`",
+                            )
+                            .emit();
+                            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
+                        }
+                        "dylib" => NativeLibKind::Dylib { as_needed: None },
+                        "framework" => NativeLibKind::Framework { as_needed: None },
                         "raw-dylib" => NativeLibKind::RawDylib,
                         k => {
                             struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
@@ -108,6 +117,71 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                 }
             }
 
+            // Do this outside the above loop so we don't depend on modifiers coming
+            // after kinds
+            if let Some(item) = items.iter().find(|item| item.has_name(sym::modifiers)) {
+                if let Some(modifiers) = item.value_str() {
+                    let span = item.name_value_literal_span().unwrap();
+                    for modifier in modifiers.as_str().split(',') {
+                        let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
+                            Some(m) => (m, modifier.starts_with('+')),
+                            None => {
+                                sess.span_err(
+                                    span,
+                                    "invalid linking modifier syntax, expected '+' or '-' prefix \
+                                    before one of: bundle, verbatim, whole-archive, as-needed",
+                                );
+                                continue;
+                            }
+                        };
+
+                        match (modifier, &mut lib.kind) {
+                            ("bundle", NativeLibKind::Static { bundle, .. }) => {
+                                *bundle = Some(value);
+                            }
+                            ("bundle", _) => sess.span_err(
+                                span,
+                                "bundle linking modifier is only compatible with \
+                                `static` linking kind",
+                            ),
+
+                            ("verbatim", _) => lib.verbatim = Some(value),
+
+                            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+                                *whole_archive = Some(value);
+                            }
+                            ("whole-archive", _) => sess.span_err(
+                                span,
+                                "whole-archive linking modifier is only compatible with \
+                                `static` linking kind",
+                            ),
+
+                            ("as-needed", NativeLibKind::Dylib { as_needed })
+                            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+                                *as_needed = Some(value);
+                            }
+                            ("as-needed", _) => sess.span_err(
+                                span,
+                                "as-needed linking modifier is only compatible with \
+                                `dylib` and `framework` linking kinds",
+                            ),
+
+                            _ => sess.span_err(
+                                span,
+                                &format!(
+                                    "unrecognized linking modifier `{}`, expected one \
+                                    of: bundle, verbatim, whole-archive, as-needed",
+                                    modifier
+                                ),
+                            ),
+                        }
+                    }
+                } else {
+                    let msg = "must be of the form `#[link(modifiers = \"...\")]`";
+                    sess.span_err(item.span(), msg);
+                }
+            }
+
             // In general we require #[link(name = "...")] but we allow
             // #[link(wasm_import_module = "...")] without the `name`.
             let requires_name = kind_specified || lib.wasm_import_module.is_none();
@@ -152,7 +226,7 @@ impl Collector<'tcx> {
             return;
         }
         let is_osx = self.tcx.sess.target.is_like_osx;
-        if lib.kind == NativeLibKind::Framework && !is_osx {
+        if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
                 Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(),
@@ -168,7 +242,9 @@ impl Collector<'tcx> {
             )
             .emit();
         }
-        if lib.kind == NativeLibKind::StaticNoBundle && !self.tcx.features().static_nobundle {
+        if matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. })
+            && !self.tcx.features().static_nobundle
+        {
             feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::static_nobundle,
@@ -193,30 +269,30 @@ impl Collector<'tcx> {
     fn process_command_line(&mut self) {
         // First, check for errors
         let mut renames = FxHashSet::default();
-        for (name, new_name, _) in &self.tcx.sess.opts.libs {
-            if let Some(ref new_name) = new_name {
+        for lib in &self.tcx.sess.opts.libs {
+            if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self
                     .libs
                     .iter()
                     .filter_map(|lib| lib.name.as_ref())
-                    .any(|n| &n.as_str() == name);
+                    .any(|n| &n.as_str() == &lib.name);
                 if new_name.is_empty() {
                     self.tcx.sess.err(&format!(
                         "an empty renaming target was specified for library `{}`",
-                        name
+                        lib.name
                     ));
                 } else if !any_duplicate {
                     self.tcx.sess.err(&format!(
                         "renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
                                                 attributes referencing this library.",
-                        name
+                        lib.name
                     ));
-                } else if !renames.insert(name) {
+                } else if !renames.insert(&lib.name) {
                     self.tcx.sess.err(&format!(
                         "multiple renamings were \
                                                 specified for library `{}` .",
-                        name
+                        lib.name
                     ));
                 }
             }
@@ -229,7 +305,7 @@ impl Collector<'tcx> {
         // it.  (This ensures that the linker is able to see symbols from
         // all possible dependent libraries before linking in the library
         // in question.)
-        for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
+        for passed_lib in &self.tcx.sess.opts.libs {
             // If we've already added any native libraries with the same
             // name, they will be pulled out into `existing`, so that we
             // can move them to the end of the list below.
@@ -237,13 +313,14 @@ impl Collector<'tcx> {
                 .libs
                 .drain_filter(|lib| {
                     if let Some(lib_name) = lib.name {
-                        if lib_name.as_str() == *name {
-                            if kind != NativeLibKind::Unspecified {
-                                lib.kind = kind;
+                        if lib_name.as_str() == passed_lib.name {
+                            if passed_lib.kind != NativeLibKind::Unspecified {
+                                lib.kind = passed_lib.kind;
                             }
-                            if let Some(new_name) = new_name {
+                            if let Some(new_name) = &passed_lib.new_name {
                                 lib.name = Some(Symbol::intern(new_name));
                             }
+                            lib.verbatim = passed_lib.verbatim;
                             return true;
                         }
                     }
@@ -252,13 +329,14 @@ impl Collector<'tcx> {
                 .collect::<Vec<_>>();
             if existing.is_empty() {
                 // Add if not found
-                let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
+                let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
                 let lib = NativeLib {
-                    name: Some(Symbol::intern(new_name.unwrap_or(name))),
-                    kind,
+                    name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
+                    kind: passed_lib.kind,
                     cfg: None,
                     foreign_module: None,
                     wasm_import_module: None,
+                    verbatim: passed_lib.verbatim,
                 };
                 self.register_native_lib(None, lib);
             } else {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 2ade1bb4f95..d74fef0045f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1885,10 +1885,6 @@ impl CrateMetadata {
         self.root.hash
     }
 
-    fn num_def_ids(&self) -> usize {
-        self.root.tables.def_keys.size()
-    }
-
     fn local_def_id(&self, index: DefIndex) -> DefId {
         DefId { krate: self.cnum, index }
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index bebee9dac3b..b11ad6c7ff8 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -256,16 +256,13 @@ pub fn provide(providers: &mut Providers) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
-            Some(NativeLibKind::Dylib | NativeLibKind::RawDylib | NativeLibKind::Unspecified) => {
-                true
-            }
+            Some(
+                NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
+            ) => true,
             _ => false,
         },
         is_statically_included_foreign_item: |tcx, id| {
-            matches!(
-                tcx.native_library_kind(id),
-                Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle)
-            )
+            matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
         },
         native_library_kind: |tcx, id| {
             tcx.native_libraries(id.krate)
@@ -461,10 +458,6 @@ impl CStore {
         self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
     }
 
-    pub fn num_def_ids(&self, cnum: CrateNum) -> usize {
-        self.get_crate_data(cnum).num_def_ids()
-    }
-
     pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
     }
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 4cd126988f9..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(true);
-        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/lib.rs b/compiler/rustc_middle/src/lib.rs
index 45ea07a3db6..597a4fd0f52 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -50,6 +50,7 @@
 #![feature(control_flow_enum)]
 #![feature(associated_type_defaults)]
 #![feature(iter_zip)]
+#![feature(thread_local_const_init)]
 #![recursion_limit = "512"]
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 26e61ec8cf8..7adaf54fa23 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -272,11 +272,13 @@ pub fn struct_lint_level<'s, 'd>(
             // emit shouldn't be automatically fixed by rustfix.
             err.allow_suggestions(false);
 
-            // If this is a future incompatible lint it'll become a hard error, so
-            // we have to emit *something*. Also, if this lint occurs in the
-            // expansion of a macro from an external crate, allow individual lints
-            // to opt-out from being reported.
-            if future_incompatible.is_none() && !lint.report_in_external_macro {
+            // If this is a future incompatible that is not an edition fixing lint
+            // it'll become a hard error, so we have to emit *something*. Also,
+            // if this lint occurs in the expansion of a macro from an external crate,
+            // allow individual lints to opt-out from being reported.
+            let not_future_incompatible =
+                future_incompatible.map(|f| f.edition.is_some()).unwrap_or(true);
+            if not_future_incompatible && !lint.report_in_external_macro {
                 err.cancel();
                 // Don't continue further, since we don't want to have
                 // `diag_span_note_once` called for a diagnostic that isn't emitted.
diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs
index 4f1ca968c30..82b9ebcc7ec 100644
--- a/compiler/rustc_middle/src/middle/cstore.rs
+++ b/compiler/rustc_middle/src/middle/cstore.rs
@@ -94,6 +94,7 @@ pub struct NativeLib {
     pub cfg: Option<ast::MetaItem>,
     pub foreign_module: Option<DefId>,
     pub wasm_import_module: Option<Symbol>,
+    pub verbatim: Option<bool>,
 }
 
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index cc0df127434..ea582d470f9 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -171,7 +171,6 @@ impl fmt::Display for InvalidProgramInfo<'_> {
 #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub enum CheckInAllocMsg {
     MemoryAccessTest,
-    NullPointerTest,
     PointerArithmeticTest,
     InboundsTest,
 }
@@ -185,7 +184,6 @@ impl fmt::Display for CheckInAllocMsg {
             "{}",
             match *self {
                 CheckInAllocMsg::MemoryAccessTest => "memory access",
-                CheckInAllocMsg::NullPointerTest => "NULL pointer test",
                 CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic",
                 CheckInAllocMsg::InboundsTest => "inbounds test",
             }
@@ -308,8 +306,8 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
                 ptr.alloc_id,
                 allocation_size.bytes()
             ),
-            DanglingIntPointer(_, CheckInAllocMsg::NullPointerTest) => {
-                write!(f, "NULL pointer is not allowed for this operation")
+            DanglingIntPointer(_, CheckInAllocMsg::InboundsTest) => {
+                write!(f, "null pointer is not allowed for this operation")
             }
             DanglingIntPointer(i, msg) => {
                 write!(f, "{} failed: 0x{:x} is not a valid pointer", msg, i)
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/query.rs b/compiler/rustc_middle/src/mir/query.rs
index fdd874c6f68..a80aa6ad3d8 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -81,7 +81,7 @@ impl UnsafetyViolationDetails {
             ),
             DerefOfRawPointer => (
                 "dereference of raw pointer",
-                "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \
+                "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
                  and cause data races: all of these are undefined behavior",
             ),
             AssignToDroppingUnionField => (
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 7e62e10821c..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()`.
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 b414618f7d5..10f7cc87c7c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1705,7 +1705,7 @@ pub mod tls {
     #[cfg(not(parallel_compiler))]
     thread_local! {
         /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
-        static TLV: Cell<usize> = Cell::new(0);
+        static TLV: Cell<usize> = const { Cell::new(0) };
     }
 
     /// Sets TLV to `value` during the call to `f`.
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 92288c89827..9faa172a497 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -141,7 +141,9 @@ impl FlagComputation {
             &ty::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
-                    ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {}
+                    ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
+                        self.add_flags(TypeFlags::HAS_TY_FRESH)
+                    }
 
                     ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
                         self.add_flags(TypeFlags::HAS_TY_INFER)
@@ -278,7 +280,7 @@ impl FlagComputation {
             ty::ConstKind::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
-                    InferConst::Fresh(_) => {}
+                    InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
                     InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 1989c91a879..174ec481ae9 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -55,10 +55,10 @@ macro_rules! define_scoped_cx {
 }
 
 thread_local! {
-    static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
-    static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
-    static NO_TRIMMED_PATH: Cell<bool> = Cell::new(false);
-    static NO_QUERIES: Cell<bool> = Cell::new(false);
+    static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };
+    static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
+    static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
+    static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
 }
 
 /// Avoids running any queries during any prints that occur
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_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 d1fb999e518..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
             }
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/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index d74ef66a4b2..69ab50fa86e 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -323,7 +323,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_scalar(result, dest)?;
             }
             sym::copy => {
-                self.copy(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
+                self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
             }
             sym::offset => {
                 let ptr = self.read_scalar(&args[0])?.check_init()?;
@@ -348,8 +348,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let b = self.read_immediate(&args[1])?.to_scalar()?;
 
                 // Special case: if both scalars are *equal integers*
-                // and not NULL, we pretend there is an allocation of size 0 right there,
-                // and their offset is 0. (There's never a valid object at NULL, making it an
+                // and not null, we pretend there is an allocation of size 0 right there,
+                // and their offset is 0. (There's never a valid object at null, making it an
                 // exception from the exception.)
                 // This is the dual to the special exception for offset-by-0
                 // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
@@ -501,7 +501,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
     /// allocation. For integer pointers, we consider each of them their own tiny allocation of size
-    /// 0, so offset-by-0 (and only 0) is okay -- except that NULL cannot be offset by _any_ value.
+    /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
     pub fn ptr_offset_inbounds(
         &self,
         ptr: Scalar<M::PointerTag>,
@@ -521,13 +521,45 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // pointers to be properly aligned (unlike a read/write operation).
         let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
         let size = offset_bytes.unsigned_abs();
-        // This call handles checking for integer/NULL pointers.
+        // This call handles checking for integer/null pointers.
         self.memory.check_ptr_access_align(
             min_ptr,
             Size::from_bytes(size),
             None,
-            CheckInAllocMsg::InboundsTest,
+            CheckInAllocMsg::PointerArithmeticTest,
         )?;
         Ok(offset_ptr)
     }
+
+    /// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`.
+    pub(crate) fn copy_intrinsic(
+        &mut self,
+        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        nonoverlapping: bool,
+    ) -> InterpResult<'tcx> {
+        let count = self.read_scalar(&count)?.to_machine_usize(self)?;
+        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
+        let (size, align) = (layout.size, layout.align.abi);
+        let size = size.checked_mul(count, self).ok_or_else(|| {
+            err_ub_format!(
+                "overflow computing total size of `{}`",
+                if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
+            )
+        })?;
+
+        // Make sure we check both pointers for an access of the total size and aligment,
+        // *even if* the total size is 0.
+        let src =
+            self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
+
+        let dst =
+            self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
+
+        if let (Some(src), Some(dst)) = (src, dst) {
+            self.memory.copy(src, dst, size, nonoverlapping)?;
+        }
+        Ok(())
+    }
 }
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index 65869f95639..52baf1a6330 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -369,6 +369,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
         Err((if int == 0 {
             // This is UB, seriously.
+            // (`DanglingIntPointer` with these exact arguments has special printing code.)
             err_ub!(DanglingIntPointer(0, CheckInAllocMsg::InboundsTest))
         } else {
             // This is just something we cannot support during const-eval.
diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs
index fe5ebf0b6fe..1aaa56403f4 100644
--- a/compiler/rustc_mir/src/interpret/memory.rs
+++ b/compiler/rustc_mir/src/interpret/memory.rs
@@ -2,7 +2,7 @@
 //!
 //! Generally, we use `Pointer` to denote memory addresses. However, some operations
 //! have a "size"-like parameter, and they take `Scalar` for the address because
-//! if the size is 0, then the pointer can also be a (properly aligned, non-NULL)
+//! if the size is 0, then the pointer can also be a (properly aligned, non-null)
 //! integer. It is crucial that these operations call `check_align` *before*
 //! short-circuiting the empty case!
 
@@ -105,7 +105,7 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
     /// Map for "extra" function pointers.
     extra_fn_ptr_map: FxHashMap<AllocId, M::ExtraFnVal>,
 
-    /// To be able to compare pointers with NULL, and to check alignment for accesses
+    /// To be able to compare pointers with null, and to check alignment for accesses
     /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
     /// that do not exist any more.
     // FIXME: this should not be public, but interning currently needs access to it
@@ -391,7 +391,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             Ok(bits) => {
                 let bits = u64::try_from(bits).unwrap(); // it's ptr-sized
                 assert!(size.bytes() == 0);
-                // Must be non-NULL.
+                // Must be non-null.
                 if bits == 0 {
                     throw_ub!(DanglingIntPointer(0, msg))
                 }
@@ -404,7 +404,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             Err(ptr) => {
                 let (allocation_size, alloc_align) =
                     self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?;
-                // Test bounds. This also ensures non-NULL.
+                // Test bounds. This also ensures non-null.
                 // It is sufficient to check this for the end pointer. The addition
                 // checks for overflow.
                 let end_ptr = ptr.offset(size, self)?;
@@ -436,7 +436,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         })
     }
 
-    /// Test if the pointer might be NULL.
+    /// Test if the pointer might be null.
     pub fn ptr_may_be_null(&self, ptr: Pointer<M::PointerTag>) -> bool {
         let (size, _align) = self
             .get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index 699b531f501..d7c11aee21f 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -375,7 +375,7 @@ where
         assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
         // Check (stricter) dynamic alignment, unless forced otherwise.
         place.mplace.align = force_align.unwrap_or(align);
-        // When dereferencing a pointer, it must be non-NULL, aligned, and live.
+        // When dereferencing a pointer, it must be non-null, aligned, and live.
         if let Some(ptr) = self.check_mplace_access(&place, Some(size))? {
             place.mplace.ptr = ptr.into();
         }
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs
index 6084f67abd7..5a10ffe6d61 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_mir/src/interpret/step.rs
@@ -2,7 +2,6 @@
 //!
 //! The main entry point is the `step` method.
 
-use crate::interpret::OpTy;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_target::abi::LayoutOf;
@@ -119,7 +118,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let src = self.eval_operand(src, None)?;
                 let dst = self.eval_operand(dst, None)?;
                 let count = self.eval_operand(count, None)?;
-                self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
+                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
             }
 
             // Statements we do not track.
@@ -149,37 +148,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub(crate) fn copy(
-        &mut self,
-        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        nonoverlapping: bool,
-    ) -> InterpResult<'tcx> {
-        let count = self.read_scalar(&count)?.to_machine_usize(self)?;
-        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
-        let (size, align) = (layout.size, layout.align.abi);
-        let size = size.checked_mul(count, self).ok_or_else(|| {
-            err_ub_format!(
-                "overflow computing total size of `{}`",
-                if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
-            )
-        })?;
-
-        // Make sure we check both pointers for an access of the total size and aligment,
-        // *even if* the total size is 0.
-        let src =
-            self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
-
-        let dst =
-            self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
-
-        if let (Some(src), Some(dst)) = (src, dst) {
-            self.memory.copy(src, dst, size, nonoverlapping)?;
-        }
-        Ok(())
-    }
-
     /// Evaluate an assignment statement.
     ///
     /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs
index 062ef7d8b4c..6e6e64d25ac 100644
--- a/compiler/rustc_mir/src/interpret/validity.rs
+++ b/compiler/rustc_mir/src/interpret/validity.rs
@@ -330,7 +330,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                         vtable,
                         3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align
                         Some(self.ecx.tcx.data_layout.pointer_align.abi),
-                        CheckInAllocMsg::InboundsTest,
+                        CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
                     ),
                     self.path,
                     err_ub!(DanglingIntPointer(..)) |
@@ -416,7 +416,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 place.ptr,
                 size,
                 Some(align),
-                CheckInAllocMsg::InboundsTest,
+                CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
             ),
             self.path,
             err_ub!(AlignmentCheckFailed { required, has }) =>
@@ -427,7 +427,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     has.bytes()
                 },
             err_ub!(DanglingIntPointer(0, _)) =>
-                { "a NULL {}", kind },
+                { "a null {}", kind },
             err_ub!(DanglingIntPointer(i, _)) =>
                 { "a dangling {} (address 0x{:x} is unallocated)", kind, i },
             err_ub!(PointerOutOfBounds { .. }) =>
@@ -662,10 +662,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
             Err(ptr) => {
                 if lo == 1 && hi == max_hi {
-                    // Only NULL is the niche.  So make sure the ptr is NOT NULL.
+                    // Only null is the niche.  So make sure the ptr is NOT null.
                     if self.ecx.memory.ptr_may_be_null(ptr) {
                         throw_validation_failure!(self.path,
-                            { "a potentially NULL pointer" }
+                            { "a potentially null pointer" }
                             expected {
                                 "something that cannot possibly fail to be {}",
                                 wrapping_range_format(valid_range, max_hi)
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs
index eaeb44289cf..c1e8f620b30 100644
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ b/compiler/rustc_mir/src/transform/coverage/mod.rs
@@ -32,7 +32,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol};
+use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
 
 /// A simple error message wrapper for `coverage::Error`s.
 #[derive(Debug)]
@@ -113,8 +113,29 @@ struct Instrumentor<'a, 'tcx> {
 impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
     fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
         let source_map = tcx.sess.source_map();
-        let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id());
-        let body_span = hir_body.value.span;
+        let def_id = mir_body.source.def_id();
+        let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id);
+
+        let mut body_span = hir_body.value.span;
+
+        if tcx.is_closure(def_id) {
+            // If the MIR function is a closure, and if the closure body span
+            // starts from a macro, but it's content is not in that macro, try
+            // to find a non-macro callsite, and instrument the spans there
+            // instead.
+            loop {
+                let expn_data = body_span.ctxt().outer_expn_data();
+                if expn_data.is_root() {
+                    break;
+                }
+                if let ExpnKind::Macro(..) = expn_data.kind {
+                    body_span = expn_data.call_site;
+                } else {
+                    break;
+                }
+            }
+        }
+
         let source_file = source_map.lookup_source_file(body_span.lo());
         let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
             fn_sig.span.ctxt() == body_span.ctxt()
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index e155b3fa773..56c97b59476 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1216,10 +1216,9 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.expect(&token::OpenDelim(token::Paren))?;
-        attrs.extend(self.parse_inner_attributes()?); // `(#![foo] a, b, ...)` is OK.
         let (es, trailing_comma) = match self.parse_seq_to_end(
             &token::CloseDelim(token::Paren),
             SeqSep::trailing_allowed(token::Comma),
@@ -1239,12 +1238,10 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
-    fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.bump(); // `[`
 
-        attrs.extend(self.parse_inner_attributes()?);
-
         let close = &token::CloseDelim(token::Bracket);
         let kind = if self.eat(close) {
             // Empty vector
@@ -1950,7 +1947,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a `match ... { ... }` expression (`match` token already eaten).
-    fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_match_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_token.span;
         let lo = self.prev_token.span;
         let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@@ -1965,7 +1962,6 @@ impl<'a> Parser<'a> {
             }
             return Err(e);
         }
-        attrs.extend(self.parse_inner_attributes()?);
 
         let mut arms: Vec<Arm> = Vec::new();
         while self.token != token::CloseDelim(token::Brace) {
@@ -2293,15 +2289,13 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_struct_expr(
         &mut self,
         pth: ast::Path,
-        mut attrs: AttrVec,
+        attrs: AttrVec,
         recover: bool,
     ) -> PResult<'a, P<Expr>> {
         let mut fields = Vec::new();
         let mut base = ast::StructRest::None;
         let mut recover_async = false;
 
-        attrs.extend(self.parse_inner_attributes()?);
-
         let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
             recover_async = true;
             e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 0f7b8ebd376..d537741c749 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -470,7 +470,7 @@ impl<'a> Parser<'a> {
     /// Is a `dyn B0 + ... + Bn` type allowed here?
     fn is_explicit_dyn_type(&mut self) -> bool {
         self.check_keyword(kw::Dyn)
-            && (self.token.uninterpolated_span().rust_2018()
+            && (!self.token.uninterpolated_span().rust_2015()
                 || self.look_ahead(1, |t| {
                     t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)
                 }))
@@ -539,7 +539,21 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, GenericBounds> {
         let mut bounds = Vec::new();
         let mut negative_bounds = Vec::new();
-        while self.can_begin_bound() {
+
+        while self.can_begin_bound() || self.token.is_keyword(kw::Dyn) {
+            if self.token.is_keyword(kw::Dyn) {
+                // Account for `&dyn Trait + dyn Other`.
+                self.struct_span_err(self.token.span, "invalid `dyn` keyword")
+                    .help("`dyn` is only needed at the start of a trait `+`-separated list")
+                    .span_suggestion(
+                        self.token.span,
+                        "remove this keyword",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                self.bump();
+            }
             match self.parse_generic_bound()? {
                 Ok(bound) => bounds.push(bound),
                 Err(neg_sp) => negative_bounds.push(neg_sp),
@@ -721,7 +735,26 @@ impl<'a> Parser<'a> {
         let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
         let path = self.parse_path(PathStyle::Type)?;
         if has_parens {
-            self.expect(&token::CloseDelim(token::Paren))?;
+            if self.token.is_like_plus() {
+                // Someone has written something like `&dyn (Trait + Other)`. The correct code
+                // would be `&(dyn Trait + Other)`, but we don't have access to the appropriate
+                // span to suggest that. When written as `&dyn Trait + Other`, an appropriate
+                // suggestion is given.
+                let bounds = vec![];
+                self.parse_remaining_bounds(bounds, true)?;
+                self.expect(&token::CloseDelim(token::Paren))?;
+                let sp = vec![lo, self.prev_token.span];
+                let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
+                self.struct_span_err(sp, "incorrect braces around trait bounds")
+                    .multipart_suggestion(
+                        "remove the parentheses",
+                        sugg,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+            } else {
+                self.expect(&token::CloseDelim(token::Paren))?;
+            }
         }
 
         let modifier = modifiers.to_trait_bound_modifier();
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index 2e4c8d0565a..011c2ceebb7 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -14,7 +14,7 @@ pub trait CacheSelector<K, V> {
     type Cache;
 }
 
-pub trait QueryStorage: Default {
+pub trait QueryStorage {
     type Value: Debug;
     type Stored: Clone;
 
@@ -23,7 +23,7 @@ pub trait QueryStorage: Default {
     fn store_nocache(&self, value: Self::Value) -> Self::Stored;
 }
 
-pub trait QueryCache: QueryStorage {
+pub trait QueryCache: QueryStorage + Sized {
     type Key: Hash + Eq + Clone + Debug;
     type Sharded: Default;
 
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 4e2515c3ac3..f2a6b6df4b9 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -52,10 +52,6 @@ impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
         (self.hash_result)(hcx, value)
     }
 
-    pub(crate) fn handle_cycle_error(&self, tcx: CTX, diag: DiagnosticBuilder<'_>) -> V {
-        (self.handle_cycle_error)(tcx, diag)
-    }
-
     pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K, value: Option<&V>) -> bool {
         (self.cache_on_disk)(tcx, key, value)
     }
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 21f580db04f..a967670280f 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -9,7 +9,6 @@ use rustc_span::Span;
 
 use std::convert::TryFrom;
 use std::hash::Hash;
-use std::marker::PhantomData;
 use std::num::NonZeroU32;
 
 #[cfg(parallel_compiler)]
@@ -100,8 +99,6 @@ pub struct QueryJob<D> {
     /// The latch that is used to wait on this job.
     #[cfg(parallel_compiler)]
     latch: Option<QueryLatch<D>>,
-
-    dummy: PhantomData<QueryLatch<D>>,
 }
 
 impl<D> QueryJob<D>
@@ -116,23 +113,17 @@ where
             parent,
             #[cfg(parallel_compiler)]
             latch: None,
-            dummy: PhantomData,
         }
     }
 
     #[cfg(parallel_compiler)]
-    pub(super) fn latch(&mut self, _id: QueryJobId<D>) -> QueryLatch<D> {
+    pub(super) fn latch(&mut self) -> QueryLatch<D> {
         if self.latch.is_none() {
             self.latch = Some(QueryLatch::new());
         }
         self.latch.as_ref().unwrap().clone()
     }
 
-    #[cfg(not(parallel_compiler))]
-    pub(super) fn latch(&mut self, id: QueryJobId<D>) -> QueryLatch<D> {
-        QueryLatch { id }
-    }
-
     /// Signals to waiters that the query is complete.
     ///
     /// This does nothing for single threaded rustc,
@@ -148,13 +139,7 @@ where
 }
 
 #[cfg(not(parallel_compiler))]
-#[derive(Clone)]
-pub(super) struct QueryLatch<D> {
-    id: QueryJobId<D>,
-}
-
-#[cfg(not(parallel_compiler))]
-impl<D> QueryLatch<D>
+impl<D> QueryJobId<D>
 where
     D: Copy + Clone + Eq + Hash,
 {
@@ -172,7 +157,7 @@ where
             let info = query_map.get(&job).unwrap();
             cycle.push(info.info.clone());
 
-            if job == self.id {
+            if job == *self {
                 cycle.reverse();
 
                 // This is the end of the cycle
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index f7b83812e89..68d2d619aab 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -11,13 +11,13 @@ use crate::query::job::{
 };
 use crate::query::{QueryContext, QueryMap, QueryStackFrame};
 
-#[cfg(not(parallel_compiler))]
-use rustc_data_structures::cold_path;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHasher};
 use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
 use rustc_data_structures::sync::{Lock, LockGuard};
 use rustc_data_structures::thin_vec::ThinVec;
+#[cfg(not(parallel_compiler))]
+use rustc_errors::DiagnosticBuilder;
 use rustc_errors::{Diagnostic, FatalError};
 use rustc_span::Span;
 use std::collections::hash_map::Entry;
@@ -36,7 +36,7 @@ pub struct QueryCacheStore<C: QueryCache> {
     pub cache_hits: AtomicUsize,
 }
 
-impl<C: QueryCache> Default for QueryCacheStore<C> {
+impl<C: QueryCache + Default> Default for QueryCacheStore<C> {
     fn default() -> Self {
         Self {
             cache: C::default(),
@@ -125,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(())
     }
@@ -161,6 +158,31 @@ where
     id: QueryJobId<D>,
 }
 
+#[cold]
+#[inline(never)]
+#[cfg(not(parallel_compiler))]
+fn mk_cycle<CTX, V, R>(
+    tcx: CTX,
+    root: QueryJobId<CTX::DepKind>,
+    span: Span,
+    handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
+    cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
+) -> R
+where
+    CTX: QueryContext,
+    V: std::fmt::Debug,
+    R: Clone,
+{
+    let error: CycleError = root.find_cycle_in_stack(
+        tcx.try_collect_active_jobs().unwrap(),
+        &tcx.current_query_job(),
+        span,
+    );
+    let error = report_cycle(tcx.dep_context().sess(), error);
+    let value = handle_cycle_error(tcx, error);
+    cache.store_nocache(value)
+}
+
 impl<'tcx, D, C> JobOwner<'tcx, D, C>
 where
     D: Copy + Clone + Eq + Hash,
@@ -180,7 +202,7 @@ where
         state: &'b QueryState<CTX::DepKind, C::Key>,
         cache: &'b QueryCacheStore<C>,
         span: Span,
-        key: &C::Key,
+        key: C::Key,
         lookup: QueryLookup,
         query: &QueryVtable<CTX, C::Key, C::Value>,
     ) -> TryGetJob<'b, CTX::DepKind, C>
@@ -191,94 +213,86 @@ where
         let mut state_lock = state.shards.get_shard_by_index(shard).lock();
         let lock = &mut *state_lock;
 
-        let (latch, mut _query_blocked_prof_timer) = match lock.active.entry((*key).clone()) {
-            Entry::Occupied(mut entry) => {
-                match entry.get_mut() {
-                    QueryResult::Started(job) => {
-                        // For parallel queries, we'll block and wait until the query running
-                        // in another thread has completed. Record how long we wait in the
-                        // self-profiler.
-                        let _query_blocked_prof_timer = if cfg!(parallel_compiler) {
-                            Some(tcx.dep_context().profiler().query_blocked())
-                        } else {
-                            None
-                        };
-
-                        // Create the id of the job we're waiting for
-                        let id = QueryJobId::new(job.id, shard, query.dep_kind);
-
-                        (job.latch(id), _query_blocked_prof_timer)
-                    }
-                    QueryResult::Poisoned => FatalError.raise(),
-                }
-            }
+        match lock.active.entry(key) {
             Entry::Vacant(entry) => {
-                // No job entry for this query. Return a new one to be started later.
-
                 // Generate an id unique within this shard.
                 let id = lock.jobs.checked_add(1).unwrap();
                 lock.jobs = id;
                 let id = QueryShardJobId(NonZeroU32::new(id).unwrap());
 
-                let global_id = QueryJobId::new(id, shard, query.dep_kind);
-
                 let job = tcx.current_query_job();
                 let job = QueryJob::new(id, span, job);
 
+                let key = entry.key().clone();
                 entry.insert(QueryResult::Started(job));
 
-                let owner = JobOwner { state, cache, id: global_id, key: (*key).clone() };
+                let global_id = QueryJobId::new(id, shard, query.dep_kind);
+                let owner = JobOwner { state, cache, id: global_id, key };
                 return TryGetJob::NotYetStarted(owner);
             }
-        };
-        mem::drop(state_lock);
-
-        // If we are single-threaded we know that we have cycle error,
-        // so we just return the error.
-        #[cfg(not(parallel_compiler))]
-        return TryGetJob::Cycle(cold_path(|| {
-            let error: CycleError = latch.find_cycle_in_stack(
-                tcx.try_collect_active_jobs().unwrap(),
-                &tcx.current_query_job(),
-                span,
-            );
-            let error = report_cycle(tcx.dep_context().sess(), error);
-            let value = query.handle_cycle_error(tcx, error);
-            cache.cache.store_nocache(value)
-        }));
-
-        // With parallel queries we might just have to wait on some other
-        // thread.
-        #[cfg(parallel_compiler)]
-        {
-            let result = latch.wait_on(tcx.current_query_job(), span);
-
-            if let Err(cycle) = result {
-                let cycle = report_cycle(tcx.dep_context().sess(), cycle);
-                let value = query.handle_cycle_error(tcx, cycle);
-                let value = cache.cache.store_nocache(value);
-                return TryGetJob::Cycle(value);
-            }
+            Entry::Occupied(mut entry) => {
+                match entry.get_mut() {
+                    #[cfg(not(parallel_compiler))]
+                    QueryResult::Started(job) => {
+                        let id = QueryJobId::new(job.id, shard, query.dep_kind);
 
-            let cached = cache
-                .cache
-                .lookup(cache, &key, |value, index| {
-                    if unlikely!(tcx.dep_context().profiler().enabled()) {
-                        tcx.dep_context().profiler().query_cache_hit(index.into());
+                        drop(state_lock);
+
+                        // If we are single-threaded we know that we have cycle error,
+                        // so we just return the error.
+                        return TryGetJob::Cycle(mk_cycle(
+                            tcx,
+                            id,
+                            span,
+                            query.handle_cycle_error,
+                            &cache.cache,
+                        ));
                     }
-                    #[cfg(debug_assertions)]
-                    {
-                        cache.cache_hits.fetch_add(1, Ordering::Relaxed);
+                    #[cfg(parallel_compiler)]
+                    QueryResult::Started(job) => {
+                        // For parallel queries, we'll block and wait until the query running
+                        // in another thread has completed. Record how long we wait in the
+                        // self-profiler.
+                        let query_blocked_prof_timer = tcx.dep_context().profiler().query_blocked();
+
+                        // Get the latch out
+                        let latch = job.latch();
+                        let key = entry.key().clone();
+
+                        drop(state_lock);
+
+                        // With parallel queries we might just have to wait on some other
+                        // thread.
+                        let result = latch.wait_on(tcx.current_query_job(), span);
+
+                        if let Err(cycle) = result {
+                            let cycle = report_cycle(tcx.dep_context().sess(), cycle);
+                            let value = (query.handle_cycle_error)(tcx, cycle);
+                            let value = cache.cache.store_nocache(value);
+                            return TryGetJob::Cycle(value);
+                        }
+
+                        let cached = cache
+                            .cache
+                            .lookup(cache, &key, |value, index| {
+                                if unlikely!(tcx.dep_context().profiler().enabled()) {
+                                    tcx.dep_context().profiler().query_cache_hit(index.into());
+                                }
+                                #[cfg(debug_assertions)]
+                                {
+                                    cache.cache_hits.fetch_add(1, Ordering::Relaxed);
+                                }
+                                (value.clone(), index)
+                            })
+                            .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
+
+                        query_blocked_prof_timer.finish_with_query_invocation_id(cached.1.into());
+
+                        return TryGetJob::JobCompleted(cached);
                     }
-                    (value.clone(), index)
-                })
-                .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
-
-            if let Some(prof_timer) = _query_blocked_prof_timer.take() {
-                prof_timer.finish_with_query_invocation_id(cached.1.into());
+                    QueryResult::Poisoned => FatalError.raise(),
+                }
             }
-
-            return TryGetJob::JobCompleted(cached);
         }
     }
 
@@ -421,7 +435,13 @@ where
     CTX: QueryContext,
 {
     let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
-        tcx, state, cache, span, &key, lookup, query,
+        tcx,
+        state,
+        cache,
+        span,
+        key.clone(),
+        lookup,
+        query,
     ) {
         TryGetJob::NotYetStarted(job) => job,
         TryGetJob::Cycle(result) => return result,
@@ -744,7 +764,13 @@ fn force_query_impl<CTX, C>(
     };
 
     let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
-        tcx, state, cache, span, &key, lookup, query,
+        tcx,
+        state,
+        cache,
+        span,
+        key.clone(),
+        lookup,
+        query,
     ) {
         TryGetJob::NotYetStarted(job) => job,
         TryGetJob::Cycle(_) => return,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index e33c374f562..7561b3df3af 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -819,6 +819,19 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             _ => false,
         };
 
+        let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| {
+            match source {
+                PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
+                | PathSource::TupleStruct(span, _) => {
+                    // We want the main underline to cover the suggested code as well for
+                    // cleaner output.
+                    err.set_span(*span);
+                    *span
+                }
+                _ => span,
+            }
+        };
+
         let mut bad_struct_syntax_suggestion = |def_id: DefId| {
             let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
 
@@ -862,18 +875,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     }
                 }
                 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
-                    let span = match &source {
-                        PathSource::Expr(Some(Expr {
-                            span, kind: ExprKind::Call(_, _), ..
-                        }))
-                        | PathSource::TupleStruct(span, _) => {
-                            // We want the main underline to cover the suggested code as well for
-                            // cleaner output.
-                            err.set_span(*span);
-                            *span
-                        }
-                        _ => span,
-                    };
+                    let span = find_span(&source, err);
                     if let Some(span) = self.def_span(def_id) {
                         err.span_label(span, &format!("`{}` defined here", path_str));
                     }
@@ -1047,6 +1049,23 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             ) if ns == ValueNS => {
                 bad_struct_syntax_suggestion(def_id);
             }
+            (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
+                match source {
+                    PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
+                        let span = find_span(&source, err);
+                        if let Some(span) = self.def_span(def_id) {
+                            err.span_label(span, &format!("`{}` defined here", path_str));
+                        }
+                        err.span_suggestion(
+                            span,
+                            &format!("use this syntax instead"),
+                            format!("{path_str}"),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => return false,
+                }
+            }
             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
                 if let Some(span) = self.def_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 1f5cb5b8abc..6956b815f19 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -5,7 +5,7 @@ pub use crate::options::*;
 
 use crate::lint;
 use crate::search_paths::SearchPath;
-use crate::utils::{CanonicalizedPath, NativeLibKind};
+use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use crate::{early_error, early_warn, Session};
 
 use rustc_data_structures::fx::FxHashSet;
@@ -816,7 +816,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     ret.reserve(6); // the minimum number of insertions
     // Target bindings.
     ret.insert((sym::target_os, Some(Symbol::intern(os))));
-    if let Some(ref fam) = sess.target.os_family {
+    for fam in &sess.target.families {
         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
         if fam == "windows" {
             ret.insert((sym::windows, None));
@@ -1027,8 +1027,11 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "",
             "Link the generated crate(s) to the specified native
                              library NAME. The optional KIND can be one of
-                             static, framework, or dylib (the default).",
-            "[KIND=]NAME",
+                             static, framework, or dylib (the default).
+                             Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
+                             may be specified each with a prefix of either '+' to
+                             enable or '-' to disable.",
+            "[KIND[:MODIFIERS]=]NAME[:RENAME]",
         ),
         make_crate_type_option(),
         opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
@@ -1591,52 +1594,127 @@ fn select_debuginfo(
     }
 }
 
-fn parse_libs(
-    matches: &getopts::Matches,
+fn parse_native_lib_kind(kind: &str, error_format: ErrorOutputType) -> NativeLibKind {
+    match kind {
+        "dylib" => NativeLibKind::Dylib { as_needed: None },
+        "framework" => NativeLibKind::Framework { as_needed: None },
+        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+        "static-nobundle" => {
+            early_warn(
+                error_format,
+                "library kind `static-nobundle` has been superseded by specifying \
+                `-bundle` on library kind `static`. Try `static:-bundle`",
+            );
+            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
+        }
+        s => early_error(
+            error_format,
+            &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
+        ),
+    }
+}
+
+fn parse_native_lib_modifiers(
+    is_nightly: bool,
+    mut kind: NativeLibKind,
+    modifiers: &str,
     error_format: ErrorOutputType,
-) -> Vec<(String, Option<String>, NativeLibKind)> {
+) -> (NativeLibKind, Option<bool>) {
+    let mut verbatim = None;
+    for modifier in modifiers.split(',') {
+        let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
+            Some(m) => (m, modifier.starts_with('+')),
+            None => early_error(
+                error_format,
+                "invalid linking modifier syntax, expected '+' or '-' prefix \
+                    before one of: bundle, verbatim, whole-archive, as-needed",
+            ),
+        };
+
+        if !is_nightly {
+            early_error(
+                error_format,
+                "linking modifiers are currently unstable and only accepted on \
+                the nightly compiler",
+            );
+        }
+
+        match (modifier, &mut kind) {
+            ("bundle", NativeLibKind::Static { bundle, .. }) => {
+                *bundle = Some(value);
+            }
+            ("bundle", _) => early_error(
+                error_format,
+                "bundle linking modifier is only compatible with \
+                    `static` linking kind",
+            ),
+
+            ("verbatim", _) => verbatim = Some(value),
+
+            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+                *whole_archive = Some(value);
+            }
+            ("whole-archive", _) => early_error(
+                error_format,
+                "whole-archive linking modifier is only compatible with \
+                    `static` linking kind",
+            ),
+
+            ("as-needed", NativeLibKind::Dylib { as_needed })
+            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+                *as_needed = Some(value);
+            }
+            ("as-needed", _) => early_error(
+                error_format,
+                "as-needed linking modifier is only compatible with \
+                    `dylib` and `framework` linking kinds",
+            ),
+
+            _ => early_error(
+                error_format,
+                &format!(
+                    "unrecognized linking modifier `{}`, expected one \
+                    of: bundle, verbatim, whole-archive, as-needed",
+                    modifier
+                ),
+            ),
+        }
+    }
+
+    (kind, verbatim)
+}
+
+fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
+    let is_nightly = nightly_options::match_is_nightly_build(matches);
     matches
         .opt_strs("l")
         .into_iter()
         .map(|s| {
-            // Parse string of the form "[KIND=]lib[:new_name]",
-            // where KIND is one of "dylib", "framework", "static".
-            let (name, kind) = match s.split_once('=') {
-                None => (s, NativeLibKind::Unspecified),
+            // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
+            // where KIND is one of "dylib", "framework", "static" and
+            // where MODIFIERS are  a comma separated list of supported modifiers
+            // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
+            // with either + or - to indicate whether it is enabled or disabled.
+            // The last value specified for a given modifier wins.
+            let (name, kind, verbatim) = match s.split_once('=') {
+                None => (s, NativeLibKind::Unspecified, None),
                 Some((kind, name)) => {
-                    let kind = match kind {
-                        "dylib" => NativeLibKind::Dylib,
-                        "framework" => NativeLibKind::Framework,
-                        "static" => NativeLibKind::StaticBundle,
-                        "static-nobundle" => NativeLibKind::StaticNoBundle,
-                        s => {
-                            early_error(
-                                error_format,
-                                &format!(
-                                    "unknown library kind `{}`, expected \
-                                     one of dylib, framework, or static",
-                                    s
-                                ),
-                            );
+                    let (kind, verbatim) = match kind.split_once(':') {
+                        None => (parse_native_lib_kind(kind, error_format), None),
+                        Some((kind, modifiers)) => {
+                            let kind = parse_native_lib_kind(kind, error_format);
+                            parse_native_lib_modifiers(is_nightly, kind, modifiers, error_format)
                         }
                     };
-                    (name.to_string(), kind)
+                    (name.to_string(), kind, verbatim)
                 }
             };
-            if kind == NativeLibKind::StaticNoBundle
-                && !nightly_options::match_is_nightly_build(matches)
-            {
-                early_error(
-                    error_format,
-                    "the library kind 'static-nobundle' is only \
-                     accepted on the nightly compiler",
-                );
-            }
+
             let (name, new_name) = match name.split_once(':') {
                 None => (name, None),
                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
             };
-            (name, new_name, kind)
+            NativeLib { name, new_name, kind, verbatim }
         })
         .collect()
 }
@@ -2316,7 +2394,7 @@ crate mod dep_tracking {
     };
     use crate::lint;
     use crate::options::WasiExecModel;
-    use crate::utils::NativeLibKind;
+    use crate::utils::{NativeLib, NativeLibKind};
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
@@ -2332,17 +2410,17 @@ crate mod dep_tracking {
     }
 
     macro_rules! impl_dep_tracking_hash_via_hash {
-        ($t:ty) => {
+        ($($t:ty),+ $(,)?) => {$(
             impl DepTrackingHash for $t {
                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
                     Hash::hash(self, hasher);
                 }
             }
-        };
+        )+};
     }
 
     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
-        ($t:ty) => {
+        ($($t:ty),+ $(,)?) => {$(
             impl DepTrackingHash for Vec<$t> {
                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
                     let mut elems: Vec<&$t> = self.iter().collect();
@@ -2354,61 +2432,66 @@ crate mod dep_tracking {
                     }
                 }
             }
-        };
-    }
+        )+};
+    }
+
+    impl_dep_tracking_hash_via_hash!(
+        bool,
+        usize,
+        u64,
+        String,
+        PathBuf,
+        lint::Level,
+        Option<bool>,
+        Option<u32>,
+        Option<usize>,
+        Option<NonZeroUsize>,
+        Option<String>,
+        Option<(String, u64)>,
+        Option<Vec<String>>,
+        Option<MergeFunctions>,
+        Option<RelocModel>,
+        Option<CodeModel>,
+        Option<TlsModel>,
+        Option<WasiExecModel>,
+        Option<PanicStrategy>,
+        Option<RelroLevel>,
+        Option<InstrumentCoverage>,
+        Option<lint::Level>,
+        Option<PathBuf>,
+        CrateType,
+        MergeFunctions,
+        PanicStrategy,
+        RelroLevel,
+        Passes,
+        OptLevel,
+        LtoCli,
+        DebugInfo,
+        UnstableFeatures,
+        OutputTypes,
+        NativeLib,
+        NativeLibKind,
+        SanitizerSet,
+        CFGuard,
+        TargetTriple,
+        Edition,
+        LinkerPluginLto,
+        Option<SplitDebuginfo>,
+        SwitchWithOptPath,
+        Option<SymbolManglingVersion>,
+        Option<SourceFileHashAlgorithm>,
+        TrimmedDefPaths,
+    );
 
-    impl_dep_tracking_hash_via_hash!(bool);
-    impl_dep_tracking_hash_via_hash!(usize);
-    impl_dep_tracking_hash_via_hash!(u64);
-    impl_dep_tracking_hash_via_hash!(String);
-    impl_dep_tracking_hash_via_hash!(PathBuf);
-    impl_dep_tracking_hash_via_hash!(lint::Level);
-    impl_dep_tracking_hash_via_hash!(Option<bool>);
-    impl_dep_tracking_hash_via_hash!(Option<u32>);
-    impl_dep_tracking_hash_via_hash!(Option<usize>);
-    impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
-    impl_dep_tracking_hash_via_hash!(Option<String>);
-    impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
-    impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
-    impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
-    impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
-    impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
-    impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
-    impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
-    impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
-    impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
-    impl_dep_tracking_hash_via_hash!(Option<InstrumentCoverage>);
-    impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
-    impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
-    impl_dep_tracking_hash_via_hash!(CrateType);
-    impl_dep_tracking_hash_via_hash!(MergeFunctions);
-    impl_dep_tracking_hash_via_hash!(PanicStrategy);
-    impl_dep_tracking_hash_via_hash!(RelroLevel);
-    impl_dep_tracking_hash_via_hash!(Passes);
-    impl_dep_tracking_hash_via_hash!(OptLevel);
-    impl_dep_tracking_hash_via_hash!(LtoCli);
-    impl_dep_tracking_hash_via_hash!(DebugInfo);
-    impl_dep_tracking_hash_via_hash!(UnstableFeatures);
-    impl_dep_tracking_hash_via_hash!(OutputTypes);
-    impl_dep_tracking_hash_via_hash!(NativeLibKind);
-    impl_dep_tracking_hash_via_hash!(SanitizerSet);
-    impl_dep_tracking_hash_via_hash!(CFGuard);
-    impl_dep_tracking_hash_via_hash!(TargetTriple);
-    impl_dep_tracking_hash_via_hash!(Edition);
-    impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
-    impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
-    impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
-    impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
-    impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
-    impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
-
-    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));
-    impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
+    impl_dep_tracking_hash_for_sortable_vec_of!(
+        String,
+        PathBuf,
+        (PathBuf, PathBuf),
+        CrateType,
+        NativeLib,
+        (String, lint::Level),
+        (String, u64)
+    );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
     where
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 1c2a7f7716d..a59f0462c73 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -3,7 +3,7 @@ use crate::config::*;
 use crate::early_error;
 use crate::lint;
 use crate::search_paths::SearchPath;
-use crate::utils::NativeLibKind;
+use crate::utils::NativeLib;
 
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
@@ -133,7 +133,7 @@ top_level_options!(
         describe_lints: bool [UNTRACKED],
         output_types: OutputTypes [TRACKED],
         search_paths: Vec<SearchPath> [UNTRACKED],
-        libs: Vec<(String, Option<String>, NativeLibKind)> [TRACKED],
+        libs: Vec<NativeLib> [TRACKED],
         maybe_sysroot: Option<PathBuf> [UNTRACKED],
 
         target_triple: TargetTriple [TRACKED],
@@ -212,7 +212,7 @@ 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,
+     $stat:ident,
      $($( #[$attr:meta] )* $opt:ident : $t:ty = (
         $init:expr,
         $parse:ident,
@@ -286,546 +286,570 @@ macro_rules! options {
 
     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`)";
+}
+
+mod parse {
+    crate use super::*;
+    use std::str::FromStr;
 
-        /// 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,
+    /// 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.
     //
@@ -935,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.
     //
@@ -1056,12 +1080,12 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "gather statistics about the input (default: no)"),
     instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
         "instrument the generated code to support LLVM source-based code coverage \
-        reports (note, the compiler build config must include `profiler = true`, \
-        and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \
-        implies `-Z symbol-mangling-version=v0`; disables/overrides some Rust \
-        optimizations. Optional values are: `=all` (default coverage), \
-        `=except-unused-generics`, `=except-unused-functions`, or `=off` \
-        (default: instrument-coverage=off)"),
+        reports (note, the compiler build config must include `profiler = true`); \
+        implies `-Z symbol-mangling-version=v0`. Optional values are:
+        `=all` (implicit value)
+        `=except-unused-generics`
+        `=except-unused-functions`
+        `=off` (default)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index e9d597d1ba6..1a044e677a0 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -19,25 +19,42 @@ impl Session {
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub enum NativeLibKind {
-    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included
-    /// when linking a final binary, but not when archiving an rlib.
-    StaticNoBundle,
-    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included
-    /// when linking a final binary, but also included when archiving an rlib.
-    StaticBundle,
+    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC)
+    Static {
+        /// Whether to bundle objects from static library into produced rlib
+        bundle: Option<bool>,
+        /// Whether to link static library without throwing any object files away
+        whole_archive: Option<bool>,
+    },
     /// Dynamic library (e.g. `libfoo.so` on Linux)
     /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC).
-    Dylib,
+    Dylib {
+        /// Whether the dynamic library will be linked only if it satifies some undefined symbols
+        as_needed: Option<bool>,
+    },
     /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library.
     RawDylib,
     /// A macOS-specific kind of dynamic libraries.
-    Framework,
+    Framework {
+        /// Whether the framework will be linked only if it satifies some undefined symbols
+        as_needed: Option<bool>,
+    },
     /// The library kind wasn't specified, `Dylib` is currently used as a default.
     Unspecified,
 }
 
 rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
 
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct NativeLib {
+    pub name: String,
+    pub new_name: Option<String>,
+    pub kind: NativeLibKind,
+    pub verbatim: Option<bool>,
+}
+
+rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
+
 /// A path that has been canonicalized along with its original, non-canonicalized form
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CanonicalizedPath {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index f75fe22767f..8b611626fca 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1330,7 +1330,7 @@ fn update_disambiguator(expn_id: ExpnId) {
             // This cache is only used by `DummyHashStableContext`,
             // so we won't pollute the cache values of the normal `StableHashingContext`
             thread_local! {
-                static CACHE: ExpnIdCache = Default::default();
+                static CACHE: ExpnIdCache = const { ExpnIdCache::new(Vec::new()) };
             }
 
             &CACHE
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index d30236ec3ec..e0bc7544246 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -20,6 +20,7 @@
 #![feature(negative_impls)]
 #![feature(nll)]
 #![feature(min_specialization)]
+#![feature(thread_local_const_init)]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b2dac10c83f..4c80b84e3d2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -748,6 +748,7 @@ symbols! {
         minnumf64,
         mips_target_feature,
         misc,
+        modifiers,
         module,
         module_path,
         more_struct_aliases,
@@ -763,6 +764,11 @@ symbols! {
         naked,
         naked_functions,
         name,
+        native_link_modifiers,
+        native_link_modifiers_as_needed,
+        native_link_modifiers_bundle,
+        native_link_modifiers_verbatim,
+        native_link_modifiers_whole_archive,
         ne,
         nearbyintf32,
         nearbyintf64,
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 6fa0b345450..bc2ec670901 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -23,7 +23,7 @@ pub fn opts(os: &str) -> TargetOptions {
         function_sections: false,
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_osx: true,
         dwarf_version: Some(2),
         has_rpath: true,
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index dd017098782..fb94498c131 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "dragonfly".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index ad3383cc5f2..5d3c28e5f29 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "freebsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 2b925f8b946..13264dffeb4 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -25,7 +25,7 @@ pub fn opts() -> TargetOptions {
         linker: Some("rust-lld".to_owned()),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_fuchsia: true,
         linker_is_gnu: true,
         pre_link_args,
diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs
index 956e4ed4bf9..fae56f6a82d 100644
--- a/compiler/rustc_target/src/spec/haiku_base.rs
+++ b/compiler/rustc_target/src/spec/haiku_base.rs
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "haiku".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         relro_level: RelroLevel::Full,
         linker_is_gnu: true,
         ..Default::default()
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index d9b5716c041..2e365d210f3 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -20,7 +20,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
         eliminate_frame_pointer: false,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index db6b74eff6d..65c343a5f21 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -20,7 +20,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         panic_strategy: PanicStrategy::Abort,
         linker: Some("ld".to_string()),
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs
index eeefd056e4b..184659e22d9 100644
--- a/compiler/rustc_target/src/spec/linux_base.rs
+++ b/compiler/rustc_target/src/spec/linux_base.rs
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "linux".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 2af46693449..dfc97447ce0 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1042,8 +1042,12 @@ pub struct TargetOptions {
     pub staticlib_prefix: String,
     /// String to append to the name of every static library. Defaults to ".a".
     pub staticlib_suffix: String,
-    /// OS family to use for conditional compilation. Valid options: "unix", "windows".
-    pub os_family: Option<String>,
+    /// Values of the `target_family` cfg set for this target.
+    ///
+    /// Common options are: "unix", "windows". Defaults to no families.
+    ///
+    /// See <https://doc.rust-lang.org/reference/conditional-compilation.html#target_family>.
+    pub families: Vec<String>,
     /// Whether the target toolchain's ABI supports returning small structs as an integer.
     pub abi_return_struct_as_int: bool,
     /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
@@ -1293,7 +1297,7 @@ impl Default for TargetOptions {
             exe_suffix: String::new(),
             staticlib_prefix: "lib".to_string(),
             staticlib_suffix: ".a".to_string(),
-            os_family: None,
+            families: Vec::new(),
             abi_return_struct_as_int: false,
             is_like_osx: false,
             is_like_solaris: false,
@@ -1605,14 +1609,6 @@ impl Target {
                         .map(|s| s.to_string() );
                 }
             } );
-            ($key_name:ident = $json_name:expr, optional) => ( {
-                let name = $json_name;
-                if let Some(o) = obj.find(name) {
-                    base.$key_name = o
-                        .as_string()
-                        .map(|s| s.to_string() );
-                }
-            } );
             ($key_name:ident, LldFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
@@ -1759,6 +1755,16 @@ impl Target {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
+            ($key_name:ident, TargetFamilies) => ( {
+                let value = obj.find("target-family");
+                if let Some(v) = value.and_then(Json::as_array) {
+                    base.$key_name = v.iter()
+                        .map(|a| a.as_string().unwrap().to_string())
+                        .collect();
+                } else if let Some(v) = value.and_then(Json::as_string) {
+                    base.$key_name = vec![v.to_string()];
+                }
+            } );
         }
 
         if let Some(s) = obj.find("target-endian").and_then(Json::as_string) {
@@ -1802,7 +1808,7 @@ impl Target {
         key!(exe_suffix);
         key!(staticlib_prefix);
         key!(staticlib_suffix);
-        key!(os_family = "target-family", optional);
+        key!(families, TargetFamilies);
         key!(abi_return_struct_as_int, bool);
         key!(is_like_osx, bool);
         key!(is_like_solaris, bool);
@@ -2042,7 +2048,7 @@ impl ToJson for Target {
         target_option_val!(exe_suffix);
         target_option_val!(staticlib_prefix);
         target_option_val!(staticlib_suffix);
-        target_option_val!(os_family, "target-family");
+        target_option_val!(families, "target-family");
         target_option_val!(abi_return_struct_as_int);
         target_option_val!(is_like_osx);
         target_option_val!(is_like_solaris);
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 680cd60788b..602fb6eb641 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "netbsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         no_default_libraries: false,
         has_rpath: true,
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index a6fd01ab110..8f33bacd922 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "openbsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         abi_return_struct_as_int: true,
diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs
index 0afb4a72ac1..72052b9e2e2 100644
--- a/compiler/rustc_target/src/spec/redox_base.rs
+++ b/compiler/rustc_target/src/spec/redox_base.rs
@@ -6,7 +6,7 @@ pub fn opts() -> TargetOptions {
         env: "relibc".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs
index 59731f25821..4c922eb5cea 100644
--- a/compiler/rustc_target/src/spec/solaris_base.rs
+++ b/compiler/rustc_target/src/spec/solaris_base.rs
@@ -6,7 +6,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
         eh_frame_header: false,
diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs
index 41c4d7625af..0e8e87f2dff 100644
--- a/compiler/rustc_target/src/spec/vxworks_base.rs
+++ b/compiler/rustc_target/src/spec/vxworks_base.rs
@@ -9,7 +9,7 @@ pub fn opts() -> TargetOptions {
         exe_suffix: ".vxe".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         has_elf_tls: true,
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index e028dbaa325..ddf28b423f0 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -38,7 +38,7 @@ pub fn target() -> Target {
         is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
         post_link_args,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         ..options
     };
     Target {
diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs
index b208eb92f8f..87e740de08e 100644
--- a/compiler/rustc_target/src/spec/wasm_base.rs
+++ b/compiler/rustc_target/src/spec/wasm_base.rs
@@ -61,6 +61,7 @@ pub fn options() -> TargetOptions {
 
     TargetOptions {
         is_like_wasm: true,
+        families: vec!["wasm".to_string()],
 
         // we allow dynamic linking, but only cdylibs. Basically we allow a
         // final library artifact that exports some symbols (a wasm module) but
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 478c567a93b..35a52896f6f 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -71,7 +71,7 @@ pub fn opts() -> TargetOptions {
         dll_prefix: String::new(),
         dll_suffix: ".dll".to_string(),
         exe_suffix: ".exe".to_string(),
-        os_family: Some("windows".to_string()),
+        families: vec!["windows".to_string()],
         is_like_windows: true,
         allows_weak_linkage: false,
         pre_link_args,
diff --git a/compiler/rustc_target/src/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs
index c041245e328..0d58618a449 100644
--- a/compiler/rustc_target/src/spec/windows_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_msvc_base.rs
@@ -13,7 +13,7 @@ pub fn opts() -> TargetOptions {
         exe_suffix: ".exe".to_string(),
         staticlib_prefix: String::new(),
         staticlib_suffix: ".lib".to_string(),
-        os_family: Some("windows".to_string()),
+        families: vec!["windows".to_string()],
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
         requires_uwtable: true,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index e4aabbdb7ed..08d452900c8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1044,8 +1044,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     /// Returns `true` if the global caches can be used.
-    /// Do note that if the type itself is not in the
-    /// global tcx, the local caches will be used.
     fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
         // If there are any inference variables in the `ParamEnv`, then we
         // always use a cache local to this particular scope. Otherwise, we
@@ -1361,7 +1359,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ) => false,
 
             (ParamCandidate(other), ParamCandidate(victim)) => {
-                if other.value == victim.value && victim.constness == Constness::NotConst {
+                let value_same_except_bound_vars = other.value.skip_binder()
+                    == victim.value.skip_binder()
+                    && !other.value.skip_binder().has_escaping_bound_vars();
+                if value_same_except_bound_vars {
+                    // See issue #84398. In short, we can generate multiple ParamCandidates which are
+                    // the same except for unused bound vars. Just pick the one with the fewest bound vars
+                    // or the current one if tied (they should both evaluate to the same answer). This is
+                    // probably best characterized as a "hack", since we might prefer to just do our
+                    // best to *not* create essentially duplicate candidates in the first place.
+                    other.value.bound_vars().len() <= victim.value.bound_vars().len()
+                } else if other.value == victim.value && victim.constness == Constness::NotConst {
                     // Drop otherwise equivalent non-const candidates in favor of const candidates.
                     true
                 } else {
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_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 8fcdf813b41..0dbcd483c45 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -59,6 +59,15 @@ bitflags! {
                                           | TypeFlags::HAS_CT_INFER.bits
                                           | TypeFlags::HAS_TY_PLACEHOLDER.bits
                                           | TypeFlags::HAS_CT_PLACEHOLDER.bits
+                                          // We consider 'freshened' types and constants
+                                          // to depend on a particular fn.
+                                          // The freshening process throws away information,
+                                          // which can make things unsuitable for use in a global
+                                          // cache. Note that there is no 'fresh lifetime' flag -
+                                          // freshening replaces all lifetimes with `ReErased`,
+                                          // which is different from how types/const are freshened.
+                                          | TypeFlags::HAS_TY_FRESH.bits
+                                          | TypeFlags::HAS_CT_FRESH.bits
                                           | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
 
         /// Does this have `Projection`?
@@ -90,6 +99,12 @@ bitflags! {
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
         const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+
+        /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
+        const HAS_TY_FRESH                = 1 << 18;
+
+        /// Does this value have `InferConst::Fresh`?
+        const HAS_CT_FRESH                = 1 << 19;
     }
 }
 
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/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index a50f8e1c655..0c6a33b91ce 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -30,6 +30,7 @@ use rustc_middle::ty::{
 use rustc_session::lint;
 use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
 use rustc_session::parse::feature_err;
+use rustc_span::edition::Edition;
 use rustc_span::source_map::{original_sp, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{self, BytePos, MultiSpan, Span};
@@ -969,20 +970,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
                 self_ty.kind
             {
-                self.tcx.struct_span_lint_hir(BARE_TRAIT_OBJECTS, hir_id, self_ty.span, |lint| {
-                    let mut db = lint
-                        .build(&format!("trait objects without an explicit `dyn` are deprecated"));
-                    let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span)
-                    {
-                        Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
-                            (format!("<dyn ({})>", s), Applicability::MachineApplicable)
-                        }
-                        Ok(s) => (format!("<dyn {}>", s), Applicability::MachineApplicable),
-                        Err(_) => ("<dyn <type>>".to_string(), Applicability::HasPlaceholders),
-                    };
-                    db.span_suggestion(self_ty.span, "use `dyn`", sugg, app);
-                    db.emit()
-                });
+                let msg = "trait objects without an explicit `dyn` are deprecated";
+                let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span) {
+                    Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
+                        (format!("<dyn ({})>", s), Applicability::MachineApplicable)
+                    }
+                    Ok(s) => (format!("<dyn {}>", s), Applicability::MachineApplicable),
+                    Err(_) => ("<dyn <type>>".to_string(), Applicability::HasPlaceholders),
+                };
+                let replace = String::from("use `dyn`");
+                if self.sess().edition() >= Edition::Edition2021 {
+                    let mut err = rustc_errors::struct_span_err!(
+                        self.sess(),
+                        self_ty.span,
+                        E0783,
+                        "{}",
+                        msg,
+                    );
+                    err.span_suggestion(
+                        self_ty.span,
+                        &sugg,
+                        replace,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                } else {
+                    self.tcx.struct_span_lint_hir(
+                        BARE_TRAIT_OBJECTS,
+                        hir_id,
+                        self_ty.span,
+                        |lint| {
+                            let mut db = lint.build(msg);
+                            db.span_suggestion(self_ty.span, &replace, sugg, app);
+                            db.emit()
+                        },
+                    );
+                }
             }
         }
     }
@@ -1282,6 +1305,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 +1314,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 +1384,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/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 73e35f0171a..b2e4e7a981d 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -579,6 +579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 let mut restrict_type_params = false;
+                let mut unsatisfied_bounds = false;
                 if !unsatisfied_predicates.is_empty() {
                     let def_span = |def_id| {
                         self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
@@ -739,6 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         err.note(&format!(
                             "the following trait bounds were not satisfied:\n{bound_list}"
                         ));
+                        unsatisfied_bounds = true;
                     }
                 }
 
@@ -752,6 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         source,
                         out_of_scope_traits,
                         &unsatisfied_predicates,
+                        unsatisfied_bounds,
                     );
                 }
 
@@ -984,9 +987,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         source: SelfSource<'tcx>,
         valid_out_of_scope_traits: Vec<DefId>,
         unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
+        unsatisfied_bounds: bool,
     ) {
         let mut alt_rcvr_sugg = false;
-        if let SelfSource::MethodCall(rcvr) = source {
+        if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
             debug!(?span, ?item_name, ?rcvr_ty, ?rcvr);
             let skippable = [
                 self.tcx.lang_items().clone_trait(),
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index d25dd9a6e83..4914f196afb 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -1298,12 +1298,14 @@ fn check_variances_for_type_defn<'tcx>(
 
         match param.name {
             hir::ParamName::Error => {}
-            _ => report_bivariance(tcx, param.span, param.name.ident().name),
+            _ => report_bivariance(tcx, param),
         }
     }
 }
 
-fn report_bivariance(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) {
+fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) {
+    let span = param.span;
+    let param_name = param.name.ident().name;
     let mut err = error_392(tcx, span, param_name);
 
     let suggested_marker_id = tcx.lang_items().phantom_data();
@@ -1318,7 +1320,14 @@ fn report_bivariance(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) {
         format!("consider removing `{}` or referring to it in a field", param_name)
     };
     err.help(&msg);
-    err.emit();
+
+    if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) {
+        err.help(&format!(
+            "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
+            param_name
+        ));
+    }
+    err.emit()
 }
 
 /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 190c9d35934..0528f8812f9 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2661,8 +2661,6 @@ 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;
@@ -2726,15 +2724,8 @@ 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);
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
         } 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) {
@@ -2945,23 +2936,6 @@ 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/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 51d5f4ebe2b..97b6f5cf412 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -191,7 +191,25 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
                     Res::Def(DefKind::Ctor(..), def_id) => {
                         tcx.generics_of(tcx.parent(def_id).unwrap())
                     }
-                    Res::Def(_, def_id) => tcx.generics_of(def_id),
+                    // Other `DefKind`s don't have generics and would ICE when calling
+                    // `generics_of`.
+                    Res::Def(
+                        DefKind::Struct
+                        | DefKind::Union
+                        | DefKind::Enum
+                        | DefKind::Variant
+                        | DefKind::Trait
+                        | DefKind::OpaqueTy
+                        | DefKind::TyAlias
+                        | DefKind::ForeignTy
+                        | DefKind::TraitAlias
+                        | DefKind::AssocTy
+                        | DefKind::Fn
+                        | DefKind::AssocFn
+                        | DefKind::AssocConst
+                        | DefKind::Impl,
+                        def_id,
+                    ) => tcx.generics_of(def_id),
                     Res::Err => {
                         tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
                         return None;
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/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index cb9daaea000..a10a027ffda 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -308,7 +308,7 @@ unsafe impl Allocator for Global {
 
 /// The allocator for unique pointers.
 // This function must not unwind. If it does, MIR codegen will fail.
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[lang = "exchange_malloc"]
 #[inline]
 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
@@ -337,6 +337,7 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
 
 // # Allocation error handler
 
+#[cfg(not(no_global_oom_handling))]
 extern "Rust" {
     // This is the magic symbol to call the global alloc error handler.  rustc generates
     // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
@@ -358,7 +359,7 @@ extern "Rust" {
 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
 #[stable(feature = "global_alloc", since = "1.28.0")]
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[rustc_allocator_nounwind]
 #[cold]
 pub fn handle_alloc_error(layout: Layout) -> ! {
@@ -368,10 +369,10 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
 }
 
 // For alloc test `std::alloc::handle_alloc_error` can be used directly.
-#[cfg(test)]
+#[cfg(all(not(no_global_oom_handling), test))]
 pub use std::alloc::handle_alloc_error;
 
-#[cfg(not(any(target_os = "hermit", test)))]
+#[cfg(all(not(no_global_oom_handling), not(any(target_os = "hermit", test))))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
 #[unstable(feature = "alloc_internals", issue = "none")]
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index bdb2d67347e..9d61b3684b8 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -4,12 +4,15 @@
 
 use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
-use core::ops::{Add, AddAssign, Deref};
+use core::ops::Deref;
+#[cfg(not(no_global_oom_handling))]
+use core::ops::{Add, AddAssign};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::borrow::{Borrow, BorrowMut};
 
 use crate::fmt;
+#[cfg(not(no_global_oom_handling))]
 use crate::string::String;
 
 use Cow::*;
@@ -429,6 +432,7 @@ impl<T: ?Sized + ToOwned> AsRef<T> for Cow<'_, T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> Add<&'a str> for Cow<'a, str> {
     type Output = Cow<'a, str>;
@@ -440,6 +444,7 @@ impl<'a> Add<&'a str> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
     type Output = Cow<'a, str>;
@@ -451,6 +456,7 @@ impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> AddAssign<&'a str> for Cow<'a, str> {
     fn add_assign(&mut self, rhs: &'a str) {
@@ -467,6 +473,7 @@ impl<'a> AddAssign<&'a str> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
     fn add_assign(&mut self, rhs: Cow<'a, str>) {
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index ef37fef0455..eb91af8c61c 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -84,7 +84,7 @@
 //! /* Returns ownership to the caller */
 //! struct Foo* foo_new(void);
 //!
-//! /* Takes ownership from the caller; no-op when invoked with NULL */
+//! /* Takes ownership from the caller; no-op when invoked with null */
 //! void foo_delete(struct Foo*);
 //! ```
 //!
@@ -139,7 +139,9 @@ use core::convert::{From, TryFrom};
 use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
-use core::iter::{FromIterator, FusedIterator, Iterator};
+#[cfg(not(no_global_oom_handling))]
+use core::iter::FromIterator;
+use core::iter::{FusedIterator, Iterator};
 use core::marker::{Unpin, Unsize};
 use core::mem;
 use core::ops::{
@@ -150,10 +152,16 @@ use core::ptr::{self, Unique};
 use core::stream::Stream;
 use core::task::{Context, Poll};
 
-use crate::alloc::{handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw};
+use crate::alloc::{AllocError, Allocator, Global, Layout};
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::Cow;
+#[cfg(not(no_global_oom_handling))]
 use crate::raw_vec::RawVec;
+#[cfg(not(no_global_oom_handling))]
 use crate::str::from_boxed_utf8_unchecked;
+#[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
 /// A pointer type for heap allocation.
@@ -177,6 +185,7 @@ impl<T> Box<T> {
     /// ```
     /// let five = Box::new(5);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline(always)]
     #[doc(alias = "alloc")]
     #[doc(alias = "malloc")]
@@ -203,6 +212,7 @@ impl<T> Box<T> {
     ///
     /// assert_eq!(*five, 5)
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
     pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
@@ -227,6 +237,7 @@ impl<T> Box<T> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[doc(alias = "calloc")]
     #[unstable(feature = "new_uninit", issue = "63291")]
@@ -236,6 +247,7 @@ impl<T> Box<T> {
 
     /// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
     /// `x` will be pinned in memory and unable to be moved.
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn pin(x: T) -> Pin<Box<T>> {
@@ -329,6 +341,7 @@ impl<T, A: Allocator> Box<T, A> {
     ///
     /// let five = Box::new_in(5, System);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn new_in(x: T, alloc: A) -> Self {
@@ -385,6 +398,7 @@ impl<T, A: Allocator> Box<T, A> {
     /// assert_eq!(*five, 5)
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[cfg(not(no_global_oom_handling))]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
@@ -447,6 +461,7 @@ impl<T, A: Allocator> Box<T, A> {
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[cfg(not(no_global_oom_handling))]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
@@ -490,6 +505,7 @@ impl<T, A: Allocator> Box<T, A> {
 
     /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement `Unpin`, then
     /// `x` will be pinned in memory and unable to be moved.
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline(always)]
     pub fn pin_in(x: T, alloc: A) -> Pin<Self>
@@ -547,6 +563,7 @@ impl<T> Box<[T]> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
         unsafe { RawVec::with_capacity(len).into_box(len) }
@@ -570,6 +587,7 @@ impl<T> Box<[T]> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
         unsafe { RawVec::with_capacity_zeroed(len).into_box(len) }
@@ -599,6 +617,7 @@ impl<T, A: Allocator> Box<[T], A> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
@@ -625,6 +644,7 @@ impl<T, A: Allocator> Box<[T], A> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
@@ -1013,6 +1033,7 @@ impl<T: Default> Default for Box<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Default for Box<[T]> {
     fn default() -> Self {
@@ -1020,6 +1041,7 @@ impl<T> Default for Box<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<str> {
     fn default() -> Self {
@@ -1027,6 +1049,7 @@ impl Default for Box<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
     /// Returns a new box with a `clone()` of this box's contents.
@@ -1076,6 +1099,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl Clone for Box<str> {
     fn clone(&self) -> Self {
@@ -1182,6 +1206,7 @@ impl<T: ?Sized + Hasher, A: Allocator> Hasher for Box<T, A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_for_ptrs", since = "1.6.0")]
 impl<T> From<T> for Box<T> {
     /// Converts a generic type `T` into a `Box<T>`
@@ -1214,6 +1239,7 @@ where
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_slice", since = "1.17.0")]
 impl<T: Copy> From<&[T]> for Box<[T]> {
     /// Converts a `&[T]` into a `Box<[T]>`
@@ -1239,6 +1265,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_cow", since = "1.45.0")]
 impl<T: Copy> From<Cow<'_, [T]>> for Box<[T]> {
     #[inline]
@@ -1250,6 +1277,7 @@ impl<T: Copy> From<Cow<'_, [T]>> for Box<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_slice", since = "1.17.0")]
 impl From<&str> for Box<str> {
     /// Converts a `&str` into a `Box<str>`
@@ -1268,6 +1296,7 @@ impl From<&str> for Box<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_cow", since = "1.45.0")]
 impl From<Cow<'_, str>> for Box<str> {
     #[inline]
@@ -1567,6 +1596,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> fo
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {}
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "boxed_slice_from_iter", since = "1.32.0")]
 impl<I> FromIterator<I> for Box<[I]> {
     fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
@@ -1574,6 +1604,7 @@ impl<I> FromIterator<I> for Box<[I]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
     fn clone(&self) -> Self {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 971244718b4..0a46387c34e 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -398,12 +398,12 @@ impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
 /// See its documentation for more.
 ///
 /// [`into_keys`]: BTreeMap::into_keys
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K: fmt::Debug, V> fmt::Debug for IntoKeys<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish()
@@ -416,12 +416,12 @@ impl<K: fmt::Debug, V> fmt::Debug for IntoKeys<K, V> {
 /// See its documentation for more.
 ///
 /// [`into_values`]: BTreeMap::into_values
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V: fmt::Debug> fmt::Debug for IntoValues<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
@@ -1242,7 +1242,6 @@ impl<K, V> BTreeMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut a = BTreeMap::new();
@@ -1253,7 +1252,7 @@ impl<K, V> BTreeMap<K, V> {
     /// assert_eq!(keys, [1, 2]);
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_keys(self) -> IntoKeys<K, V> {
         IntoKeys { inner: self.into_iter() }
     }
@@ -1265,7 +1264,6 @@ impl<K, V> BTreeMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut a = BTreeMap::new();
@@ -1276,7 +1274,7 @@ impl<K, V> BTreeMap<K, V> {
     /// assert_eq!(values, ["hello", "goodbye"]);
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_values(self) -> IntoValues<K, V> {
         IntoValues { inner: self.into_iter() }
     }
@@ -1776,7 +1774,7 @@ impl<'a, K, V> Range<'a, K, V> {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoKeys<K, V> {
     type Item = K;
 
@@ -1801,24 +1799,24 @@ impl<K, V> Iterator for IntoKeys<K, V> {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> DoubleEndedIterator for IntoKeys<K, V> {
     fn next_back(&mut self) -> Option<K> {
         self.inner.next_back().map(|(k, _)| k)
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoKeys<K, V> {}
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoValues<K, V> {
     type Item = V;
 
@@ -1835,21 +1833,21 @@ impl<K, V> Iterator for IntoValues<K, V> {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> DoubleEndedIterator for IntoValues<K, V> {
     fn next_back(&mut self) -> Option<V> {
         self.inner.next_back().map(|(_, v)| v)
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoValues<K, V> {
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoValues<K, V> {}
 
 #[stable(feature = "btree_range", since = "1.17.0")]
diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs
index 8213e904fba..b9b3d650ea2 100644
--- a/library/alloc/src/collections/mod.rs
+++ b/library/alloc/src/collections/mod.rs
@@ -2,11 +2,16 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(not(no_global_oom_handling))]
 pub mod binary_heap;
+#[cfg(not(no_global_oom_handling))]
 mod btree;
+#[cfg(not(no_global_oom_handling))]
 pub mod linked_list;
+#[cfg(not(no_global_oom_handling))]
 pub mod vec_deque;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_map {
     //! A map based on a B-Tree.
@@ -14,6 +19,7 @@ pub mod btree_map {
     pub use super::btree::map::*;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_set {
     //! A set based on a B-Tree.
@@ -21,22 +27,27 @@ pub mod btree_set {
     pub use super::btree::set::*;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use binary_heap::BinaryHeap;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use btree_map::BTreeMap;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use btree_set::BTreeSet;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use linked_list::LinkedList;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use vec_deque::VecDeque;
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index 3ef55f06e51..fd5ee189fbf 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -546,6 +546,7 @@ pub use core::fmt::{LowerExp, UpperExp};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::fmt::{LowerHex, Pointer, UpperHex};
 
+#[cfg(not(no_global_oom_handling))]
 use crate::string;
 
 /// The `format` function takes an [`Arguments`] struct and returns the resulting
@@ -574,6 +575,7 @@ use crate::string;
 ///
 /// [`format_args!`]: core::format_args
 /// [`format!`]: crate::format
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn format(args: Arguments<'_>) -> string::String {
     let capacity = args.estimated_capacity();
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 15308a4469b..66b1036f2ab 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -87,7 +87,7 @@
 #![feature(cfg_sanitize)]
 #![feature(cfg_target_has_atomic)]
 #![feature(coerce_unsized)]
-#![feature(const_btree_new)]
+#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
 #![cfg_attr(bootstrap, feature(const_fn))]
 #![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
 #![feature(cow_is_borrowed)]
@@ -183,7 +183,7 @@ pub mod str;
 pub mod string;
 #[cfg(target_has_atomic = "ptr")]
 pub mod sync;
-#[cfg(target_has_atomic = "ptr")]
+#[cfg(all(not(no_global_oom_handling), target_has_atomic = "ptr"))]
 pub mod task;
 #[cfg(test)]
 mod tests;
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index fe87a97bac1..2e2c9b76bd4 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -9,13 +9,16 @@ use core::ops::Drop;
 use core::ptr::{self, NonNull, Unique};
 use core::slice;
 
-use crate::alloc::{handle_alloc_error, Allocator, Global, Layout};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::handle_alloc_error;
+use crate::alloc::{Allocator, Global, Layout};
 use crate::boxed::Box;
 use crate::collections::TryReserveError::{self, *};
 
 #[cfg(test)]
 mod tests;
 
+#[cfg(not(no_global_oom_handling))]
 enum AllocInit {
     /// The contents of the new memory are uninitialized.
     Uninitialized,
@@ -82,12 +85,14 @@ impl<T> RawVec<T, Global> {
     /// # Aborts
     ///
     /// Aborts on OOM.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
         Self::with_capacity_in(capacity, Global)
     }
 
     /// Like `with_capacity`, but guarantees the buffer is zeroed.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_zeroed(capacity: usize) -> Self {
         Self::with_capacity_zeroed_in(capacity, Global)
@@ -131,6 +136,7 @@ impl<T, A: Allocator> RawVec<T, A> {
 
     /// Like `with_capacity`, but parameterized over the choice of
     /// allocator for the returned `RawVec`.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
         Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
@@ -138,6 +144,7 @@ impl<T, A: Allocator> RawVec<T, A> {
 
     /// Like `with_capacity_zeroed`, but parameterized over the choice
     /// of allocator for the returned `RawVec`.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
         Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
@@ -177,6 +184,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
         if mem::size_of::<T>() == 0 {
             Self::new_in(alloc)
@@ -309,6 +317,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// #   vector.push_all(&[1, 3, 5, 7, 9]);
     /// # }
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn reserve(&mut self, len: usize, additional: usize) {
         // Callers expect this function to be very cheap when there is already sufficient capacity.
@@ -355,6 +364,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// # Aborts
     ///
     /// Aborts on OOM.
+    #[cfg(not(no_global_oom_handling))]
     pub fn reserve_exact(&mut self, len: usize, additional: usize) {
         handle_reserve(self.try_reserve_exact(len, additional));
     }
@@ -378,6 +388,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// # Aborts
     ///
     /// Aborts on OOM.
+    #[cfg(not(no_global_oom_handling))]
     pub fn shrink_to_fit(&mut self, amount: usize) {
         handle_reserve(self.shrink(amount));
     }
@@ -452,6 +463,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         Ok(())
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn shrink(&mut self, amount: usize) -> Result<(), TryReserveError> {
         assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity");
 
@@ -512,6 +524,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
 }
 
 // Central function for reserve error handling.
+#[cfg(not(no_global_oom_handling))]
 #[inline]
 fn handle_reserve(result: Result<(), TryReserveError>) {
     match result {
@@ -542,6 +555,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
 // One central function responsible for reporting capacity overflows. This'll
 // ensure that the code generation related to these panics is minimal as there's
 // only one location which panics rather than a bunch throughout the module.
+#[cfg(not(no_global_oom_handling))]
 fn capacity_overflow() -> ! {
     panic!("capacity overflow");
 }
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index cb4af7c5cd1..964169a227f 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -255,19 +255,27 @@ use core::convert::{From, TryFrom};
 use core::fmt;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::abort;
+#[cfg(not(no_global_oom_handling))]
 use core::iter;
 use core::marker::{self, PhantomData, Unpin, Unsize};
-use core::mem::{self, align_of_val_raw, forget, size_of_val};
+#[cfg(not(no_global_oom_handling))]
+use core::mem::size_of_val;
+use core::mem::{self, align_of_val_raw, forget};
 use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
+#[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
 
-use crate::alloc::{
-    box_free, handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw,
-};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::handle_alloc_error;
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::{box_free, WriteCloneIntoRaw};
+use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
+#[cfg(not(no_global_oom_handling))]
 use crate::string::String;
+#[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
 #[cfg(test)]
@@ -434,6 +442,7 @@ impl<T> Rc<T> {
     ///
     /// assert_eq!(*five, 5)
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
         unsafe {
@@ -465,6 +474,7 @@ impl<T> Rc<T> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed() -> Rc<mem::MaybeUninit<T>> {
         unsafe {
@@ -637,6 +647,7 @@ impl<T> Rc<[T]> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
         unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) }
@@ -662,6 +673,7 @@ impl<T> Rc<[T]> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
         unsafe {
@@ -1122,6 +1134,7 @@ impl<T: Clone> Rc<T> {
     /// assert!(76 == *data);
     /// assert!(weak.upgrade().is_none());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rc_unique", since = "1.4.0")]
     pub fn make_mut(this: &mut Self) -> &mut T {
@@ -1195,6 +1208,7 @@ impl<T: ?Sized> Rc<T> {
     ///
     /// The function `mem_to_rcbox` is called with the data pointer
     /// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_layout(
         value_layout: Layout,
         allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
@@ -1245,6 +1259,7 @@ impl<T: ?Sized> Rc<T> {
     }
 
     /// Allocates an `RcBox<T>` with sufficient space for an unsized inner value
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
         // Allocate for the `RcBox<T>` using the given value.
         unsafe {
@@ -1256,6 +1271,7 @@ impl<T: ?Sized> Rc<T> {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn from_box(v: Box<T>) -> Rc<T> {
         unsafe {
             let (box_unique, alloc) = Box::into_unique(v);
@@ -1281,6 +1297,7 @@ impl<T: ?Sized> Rc<T> {
 
 impl<T> Rc<[T]> {
     /// Allocates an `RcBox<[T]>` with the given length.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
         unsafe {
             Self::allocate_for_layout(
@@ -1294,6 +1311,7 @@ impl<T> Rc<[T]> {
     /// Copy elements from slice into newly allocated Rc<\[T\]>
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
         unsafe {
             let ptr = Self::allocate_for_slice(v.len());
@@ -1305,6 +1323,7 @@ impl<T> Rc<[T]> {
     /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size.
     ///
     /// Behavior is undefined should the size be wrong.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn from_iter_exact(iter: impl iter::Iterator<Item = T>, len: usize) -> Rc<[T]> {
         // Panic guard while cloning T elements.
         // In the event of a panic, elements that have been written
@@ -1356,6 +1375,7 @@ trait RcFromSlice<T> {
     fn from_slice(slice: &[T]) -> Self;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
     #[inline]
     default fn from_slice(v: &[T]) -> Self {
@@ -1363,6 +1383,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Copy> RcFromSlice<T> for Rc<[T]> {
     #[inline]
     fn from_slice(v: &[T]) -> Self {
@@ -1717,6 +1738,7 @@ impl<T> From<T> for Rc<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: Clone> From<&[T]> for Rc<[T]> {
     /// Allocate a reference-counted slice and fill it by cloning `v`'s items.
@@ -1735,6 +1757,7 @@ impl<T: Clone> From<&[T]> for Rc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<&str> for Rc<str> {
     /// Allocate a reference-counted string slice and copy `v` into it.
@@ -1753,6 +1776,7 @@ impl From<&str> for Rc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<String> for Rc<str> {
     /// Allocate a reference-counted string slice and copy `v` into it.
@@ -1771,6 +1795,7 @@ impl From<String> for Rc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: ?Sized> From<Box<T>> for Rc<T> {
     /// Move a boxed object to a new, reference counted, allocation.
@@ -1789,6 +1814,7 @@ impl<T: ?Sized> From<Box<T>> for Rc<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T> From<Vec<T>> for Rc<[T]> {
     /// Allocate a reference-counted slice and move `v`'s items into it.
@@ -1842,6 +1868,7 @@ impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_iter", since = "1.37.0")]
 impl<T> iter::FromIterator<T> for Rc<[T]> {
     /// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`.
@@ -1888,16 +1915,19 @@ impl<T> iter::FromIterator<T> for Rc<[T]> {
 }
 
 /// Specialization trait used for collecting into `Rc<[T]>`.
+#[cfg(not(no_global_oom_handling))]
 trait ToRcSlice<T>: Iterator<Item = T> + Sized {
     fn to_rc_slice(self) -> Rc<[T]>;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: Iterator<Item = T>> ToRcSlice<T> for I {
     default fn to_rc_slice(self) -> Rc<[T]> {
         self.collect::<Vec<T>>().into()
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
     fn to_rc_slice(self) -> Rc<[T]> {
         // This is the case for a `TrustedLen` iterator.
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index f5d0e911b60..dcd64899204 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -83,11 +83,19 @@
 #![cfg_attr(test, allow(unused_imports, dead_code))]
 
 use core::borrow::{Borrow, BorrowMut};
+#[cfg(not(no_global_oom_handling))]
 use core::cmp::Ordering::{self, Less};
-use core::mem::{self, size_of};
+#[cfg(not(no_global_oom_handling))]
+use core::mem;
+#[cfg(not(no_global_oom_handling))]
+use core::mem::size_of;
+#[cfg(not(no_global_oom_handling))]
 use core::ptr;
 
-use crate::alloc::{Allocator, Global};
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::Global;
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::ToOwned;
 use crate::boxed::Box;
 use crate::vec::Vec;
@@ -158,17 +166,20 @@ mod hack {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn to_vec<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Vec<T, A> {
         T::to_vec(s, alloc)
     }
 
+    #[cfg(not(no_global_oom_handling))]
     pub trait ConvertVec {
         fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
         where
             Self: Sized;
     }
 
+    #[cfg(not(no_global_oom_handling))]
     impl<T: Clone> ConvertVec for T {
         #[inline]
         default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
@@ -205,6 +216,7 @@ mod hack {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     impl<T: Copy> ConvertVec for T {
         #[inline]
         fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
@@ -250,6 +262,7 @@ impl<T> [T] {
     /// v.sort();
     /// assert!(v == [-5, -3, 1, 2, 4]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sort(&mut self)
@@ -304,6 +317,7 @@ impl<T> [T] {
     /// v.sort_by(|a, b| b.cmp(a));
     /// assert!(v == [5, 4, 3, 2, 1]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sort_by<F>(&mut self, mut compare: F)
@@ -344,6 +358,7 @@ impl<T> [T] {
     /// v.sort_by_key(|k| k.abs());
     /// assert!(v == [1, 2, -3, 4, -5]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "slice_sort_by_key", since = "1.7.0")]
     #[inline]
     pub fn sort_by_key<K, F>(&mut self, mut f: F)
@@ -386,6 +401,7 @@ impl<T> [T] {
     /// ```
     ///
     /// [pdqsort]: https://github.com/orlp/pdqsort
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")]
     #[inline]
     pub fn sort_by_cached_key<K, F>(&mut self, f: F)
@@ -443,6 +459,7 @@ impl<T> [T] {
     /// let x = s.to_vec();
     /// // Here, `s` and `x` can be modified independently.
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[rustc_conversion_suggestion]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -466,6 +483,7 @@ impl<T> [T] {
     /// let x = s.to_vec_in(System);
     /// // Here, `s` and `x` can be modified independently.
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
@@ -517,6 +535,7 @@ impl<T> [T] {
     /// // this will panic at runtime
     /// b"0123456789abcdef".repeat(usize::MAX);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "repeat_generic_slice", since = "1.40.0")]
     pub fn repeat(&self, n: usize) -> Vec<T>
     where
@@ -642,6 +661,7 @@ impl [u8] {
     /// To uppercase the value in-place, use [`make_ascii_uppercase`].
     ///
     /// [`make_ascii_uppercase`]: slice::make_ascii_uppercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_uppercase(&self) -> Vec<u8> {
@@ -659,6 +679,7 @@ impl [u8] {
     /// To lowercase the value in-place, use [`make_ascii_lowercase`].
     ///
     /// [`make_ascii_lowercase`]: slice::make_ascii_lowercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_lowercase(&self) -> Vec<u8> {
@@ -724,6 +745,7 @@ pub trait Join<Separator> {
     fn join(slice: &Self, sep: Separator) -> Self::Output;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<T: Clone, V: Borrow<[T]>> Concat<T> for [V] {
     type Output = Vec<T>;
@@ -738,6 +760,7 @@ impl<T: Clone, V: Borrow<[T]>> Concat<T> for [V] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<T: Clone, V: Borrow<[T]>> Join<&T> for [V] {
     type Output = Vec<T>;
@@ -760,6 +783,7 @@ impl<T: Clone, V: Borrow<[T]>> Join<&T> for [V] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<T: Clone, V: Borrow<[T]>> Join<&[T]> for [V] {
     type Output = Vec<T>;
@@ -801,6 +825,7 @@ impl<T> BorrowMut<[T]> for Vec<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone> ToOwned for [T] {
     type Owned = Vec<T>;
@@ -835,6 +860,7 @@ impl<T: Clone> ToOwned for [T] {
 /// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted.
 ///
 /// This is the integral subroutine of insertion sort.
+#[cfg(not(no_global_oom_handling))]
 fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
 where
     F: FnMut(&T, &T) -> bool,
@@ -906,6 +932,7 @@ where
 ///
 /// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough
 /// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type.
+#[cfg(not(no_global_oom_handling))]
 unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
 where
     F: FnMut(&T, &T) -> bool,
@@ -1026,6 +1053,7 @@ where
 /// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len`
 ///
 /// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case.
+#[cfg(not(no_global_oom_handling))]
 fn merge_sort<T, F>(v: &mut [T], mut is_less: F)
 where
     F: FnMut(&T, &T) -> bool,
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 879af7cf4dd..57279e81a95 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -74,6 +74,7 @@ pub use core::str::{RSplitTerminator, SplitTerminator};
 
 /// Note: `str` in `Concat<str>` is not meaningful here.
 /// This type parameter of the trait only exists to enable another impl.
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<S: Borrow<str>> Concat<str> for [S] {
     type Output = String;
@@ -83,6 +84,7 @@ impl<S: Borrow<str>> Concat<str> for [S] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<S: Borrow<str>> Join<&str> for [S] {
     type Output = String;
@@ -92,6 +94,7 @@ impl<S: Borrow<str>> Join<&str> for [S] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 macro_rules! specialize_for_lengths {
     ($separator:expr, $target:expr, $iter:expr; $($num:expr),*) => {{
         let mut target = $target;
@@ -122,6 +125,7 @@ macro_rules! specialize_for_lengths {
     }}
 }
 
+#[cfg(not(no_global_oom_handling))]
 macro_rules! copy_slice_and_advance {
     ($target:expr, $bytes:expr) => {
         let len = $bytes.len();
@@ -139,6 +143,7 @@ macro_rules! copy_slice_and_advance {
 // the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
 // [T] and str both impl AsRef<[T]> for some T
 // => s.borrow().as_ref() and we always have slices
+#[cfg(not(no_global_oom_handling))]
 fn join_generic_copy<B, T, S>(slice: &[S], sep: &[T]) -> Vec<T>
 where
     T: Copy,
@@ -205,6 +210,7 @@ impl BorrowMut<str> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToOwned for str {
     type Owned = String;
@@ -264,6 +270,7 @@ impl str {
     /// let s = "this is old";
     /// assert_eq!(s, s.replace("cookie monster", "little lamb"));
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -303,6 +310,7 @@ impl str {
     /// let s = "this is old";
     /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10));
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "str_replacen", since = "1.16.0")]
@@ -358,6 +366,7 @@ impl str {
     ///
     /// assert_eq!(new_year, new_year.to_lowercase());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_lowercase(&self) -> String {
         let mut s = String::with_capacity(self.len());
@@ -437,6 +446,7 @@ impl str {
     ///
     /// assert_eq!("TSCHÜSS", s.to_uppercase());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_uppercase(&self) -> String {
         let mut s = String::with_capacity(self.len());
@@ -496,6 +506,7 @@ impl str {
     /// // this will panic at runtime
     /// "0123456789abcdef".repeat(usize::MAX);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "repeat_str", since = "1.16.0")]
     pub fn repeat(&self, n: usize) -> String {
         unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
@@ -522,6 +533,7 @@ impl str {
     ///
     /// [`make_ascii_uppercase`]: str::make_ascii_uppercase
     /// [`to_uppercase`]: #method.to_uppercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_uppercase(&self) -> String {
@@ -552,6 +564,7 @@ impl str {
     ///
     /// [`make_ascii_lowercase`]: str::make_ascii_lowercase
     /// [`to_lowercase`]: #method.to_lowercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_lowercase(&self) -> String {
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index f4ec4a36ffd..e6252452470 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -42,20 +42,33 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(not(no_global_oom_handling))]
 use core::char::{decode_utf16, REPLACEMENT_CHARACTER};
 use core::fmt;
 use core::hash;
-use core::iter::{FromIterator, FusedIterator};
+#[cfg(not(no_global_oom_handling))]
+use core::iter::FromIterator;
+use core::iter::FusedIterator;
+#[cfg(not(no_global_oom_handling))]
+use core::ops::Add;
+#[cfg(not(no_global_oom_handling))]
+use core::ops::AddAssign;
+#[cfg(not(no_global_oom_handling))]
 use core::ops::Bound::{Excluded, Included, Unbounded};
-use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
+use core::ops::{self, Index, IndexMut, Range, RangeBounds};
 use core::ptr;
 use core::slice;
-use core::str::{lossy, pattern::Pattern};
+#[cfg(not(no_global_oom_handling))]
+use core::str::lossy;
+use core::str::pattern::Pattern;
 
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::collections::TryReserveError;
-use crate::str::{self, from_boxed_utf8_unchecked, Chars, FromStr, Utf8Error};
+use crate::str::{self, Chars, Utf8Error};
+#[cfg(not(no_global_oom_handling))]
+use crate::str::{from_boxed_utf8_unchecked, FromStr};
 use crate::vec::Vec;
 
 /// A UTF-8–encoded, growable string.
@@ -314,7 +327,8 @@ pub struct String {
 /// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes());
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(not(no_global_oom_handling), derive(Clone))]
+#[derive(Debug, PartialEq, Eq)]
 pub struct FromUtf8Error {
     bytes: Vec<u8>,
     error: Utf8Error,
@@ -403,6 +417,7 @@ impl String {
     /// // ...but this may make the string reallocate
     /// s.push('a');
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[doc(alias = "alloc")]
     #[doc(alias = "malloc")]
@@ -535,6 +550,7 @@ impl String {
     ///
     /// assert_eq!("Hello �World", output);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
         let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks();
@@ -587,6 +603,7 @@ impl String {
     ///           0xD800, 0x0069, 0x0063];
     /// assert!(String::from_utf16(v).is_err());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
         // This isn't done via collect::<Result<_, _>>() for performance reasons.
@@ -626,6 +643,7 @@ impl String {
     /// assert_eq!(String::from("𝄞mus\u{FFFD}ic\u{FFFD}"),
     ///            String::from_utf16_lossy(v));
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf16_lossy(v: &[u16]) -> String {
@@ -818,6 +836,7 @@ impl String {
     ///
     /// assert_eq!("foobar", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_str(&mut self, string: &str) {
@@ -885,6 +904,7 @@ impl String {
     /// // ... doesn't actually increase.
     /// assert_eq!(10, s.capacity());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve(&mut self, additional: usize) {
@@ -932,6 +952,7 @@ impl String {
     /// // ... doesn't actually increase.
     /// assert_eq!(10, s.capacity());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve_exact(&mut self, additional: usize) {
@@ -1026,6 +1047,7 @@ impl String {
     /// s.shrink_to_fit();
     /// assert_eq!(3, s.capacity());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn shrink_to_fit(&mut self) {
@@ -1053,6 +1075,7 @@ impl String {
     /// s.shrink_to(0);
     /// assert!(s.capacity() >= 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
@@ -1074,6 +1097,7 @@ impl String {
     ///
     /// assert_eq!("abc123", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push(&mut self, ch: char) {
@@ -1222,6 +1246,7 @@ impl String {
     /// s.remove_matches("ana");
     /// assert_eq!("bna", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")]
     pub fn remove_matches<'a, P>(&'a mut self, pat: P)
     where
@@ -1352,6 +1377,7 @@ impl String {
     ///
     /// assert_eq!("foo", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, idx: usize, ch: char) {
@@ -1364,6 +1390,7 @@ impl String {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
         let len = self.len();
         let amt = bytes.len();
@@ -1397,6 +1424,7 @@ impl String {
     ///
     /// assert_eq!("foobar", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "insert_str", since = "1.16.0")]
     pub fn insert_str(&mut self, idx: usize, string: &str) {
@@ -1502,6 +1530,7 @@ impl String {
     /// assert_eq!(world, "World!");
     /// # }
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "string_split_off", since = "1.16.0")]
     #[must_use = "use `.truncate()` if you don't need the other half"]
@@ -1608,6 +1637,7 @@ impl String {
     /// s.replace_range(..beta_offset, "Α is capital alpha; ");
     /// assert_eq!(s, "Α is capital alpha; β is beta");
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "splice", since = "1.27.0")]
     pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
     where
@@ -1654,6 +1684,7 @@ impl String {
     ///
     /// let b = s.into_boxed_str();
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "box_str", since = "1.4.0")]
     #[inline]
     pub fn into_boxed_str(self) -> Box<str> {
@@ -1748,6 +1779,7 @@ impl fmt::Display for FromUtf16Error {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Clone for String {
     fn clone(&self) -> Self {
@@ -1759,6 +1791,7 @@ impl Clone for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl FromIterator<char> for String {
     fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String {
@@ -1768,6 +1801,7 @@ impl FromIterator<char> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_from_iter_by_ref", since = "1.17.0")]
 impl<'a> FromIterator<&'a char> for String {
     fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> String {
@@ -1777,6 +1811,7 @@ impl<'a> FromIterator<&'a char> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> FromIterator<&'a str> for String {
     fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> String {
@@ -1786,6 +1821,7 @@ impl<'a> FromIterator<&'a str> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_string", since = "1.4.0")]
 impl FromIterator<String> for String {
     fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String {
@@ -1804,6 +1840,7 @@ impl FromIterator<String> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
 impl FromIterator<Box<str>> for String {
     fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String {
@@ -1813,6 +1850,7 @@ impl FromIterator<Box<str>> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "herd_cows", since = "1.19.0")]
 impl<'a> FromIterator<Cow<'a, str>> for String {
     fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String {
@@ -1832,6 +1870,7 @@ impl<'a> FromIterator<Cow<'a, str>> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Extend<char> for String {
     fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
@@ -1852,6 +1891,7 @@ impl Extend<char> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_ref", since = "1.2.0")]
 impl<'a> Extend<&'a char> for String {
     fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
@@ -1869,6 +1909,7 @@ impl<'a> Extend<&'a char> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Extend<&'a str> for String {
     fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
@@ -1881,6 +1922,7 @@ impl<'a> Extend<&'a str> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
 impl Extend<Box<str>> for String {
     fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
@@ -1888,6 +1930,7 @@ impl Extend<Box<str>> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_string", since = "1.4.0")]
 impl Extend<String> for String {
     fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
@@ -1900,6 +1943,7 @@ impl Extend<String> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "herd_cows", since = "1.19.0")]
 impl<'a> Extend<Cow<'a, str>> for String {
     fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
@@ -2001,8 +2045,11 @@ macro_rules! impl_eq {
 
 impl_eq! { String, str }
 impl_eq! { String, &'a str }
+#[cfg(not(no_global_oom_handling))]
 impl_eq! { Cow<'a, str>, str }
+#[cfg(not(no_global_oom_handling))]
 impl_eq! { Cow<'a, str>, &'b str }
+#[cfg(not(no_global_oom_handling))]
 impl_eq! { Cow<'a, str>, String }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2075,6 +2122,7 @@ impl hash::Hash for String {
 /// let b = " world";
 /// let c = a.to_string() + b;
 /// ```
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Add<&str> for String {
     type Output = String;
@@ -2089,6 +2137,7 @@ impl Add<&str> for String {
 /// Implements the `+=` operator for appending to a `String`.
 ///
 /// This has the same behavior as the [`push_str`][String::push_str] method.
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "stringaddassign", since = "1.12.0")]
 impl AddAssign<&str> for String {
     #[inline]
@@ -2221,6 +2270,7 @@ impl ops::DerefMut for String {
 #[stable(feature = "str_parse_error", since = "1.5.0")]
 pub type ParseError = core::convert::Infallible;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl FromStr for String {
     type Err = core::convert::Infallible;
@@ -2264,6 +2314,7 @@ pub trait ToString {
 /// if the `Display` implementation returns an error.
 /// This indicates an incorrect `Display` implementation
 /// since `fmt::Write for String` never returns an error itself.
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: fmt::Display + ?Sized> ToString for T {
     // A common guideline is to not inline generic functions. However,
@@ -2280,6 +2331,7 @@ impl<T: fmt::Display + ?Sized> ToString for T {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "char_to_string_specialization", since = "1.46.0")]
 impl ToString for char {
     #[inline]
@@ -2288,6 +2340,50 @@ impl ToString for char {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "u8_to_string_specialization", since = "1.54.0")]
+impl ToString for u8 {
+    #[inline]
+    fn to_string(&self) -> String {
+        let mut buf = String::with_capacity(3);
+        let mut n = *self;
+        if n >= 10 {
+            if n >= 100 {
+                buf.push((b'0' + n / 100) as char);
+                n %= 100;
+            }
+            buf.push((b'0' + n / 10) as char);
+            n %= 10;
+        }
+        buf.push((b'0' + n) as char);
+        buf
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "i8_to_string_specialization", since = "1.54.0")]
+impl ToString for i8 {
+    #[inline]
+    fn to_string(&self) -> String {
+        let mut buf = String::with_capacity(4);
+        if self.is_negative() {
+            buf.push('-');
+        }
+        let mut n = self.unsigned_abs();
+        if n >= 10 {
+            if n >= 100 {
+                buf.push('1');
+                n -= 100;
+            }
+            buf.push((b'0' + n / 10) as char);
+            n %= 10;
+        }
+        buf.push((b'0' + n) as char);
+        buf
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "str_to_string_specialization", since = "1.9.0")]
 impl ToString for str {
     #[inline]
@@ -2296,6 +2392,7 @@ impl ToString for str {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_to_string_specialization", since = "1.17.0")]
 impl ToString for Cow<'_, str> {
     #[inline]
@@ -2304,6 +2401,7 @@ impl ToString for Cow<'_, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_to_string_specialization", since = "1.17.0")]
 impl ToString for String {
     #[inline]
@@ -2336,6 +2434,7 @@ impl AsRef<[u8]> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<&str> for String {
     #[inline]
@@ -2344,6 +2443,7 @@ impl From<&str> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_mut_str_for_string", since = "1.44.0")]
 impl From<&mut str> for String {
     /// Converts a `&mut str` into a `String`.
@@ -2355,6 +2455,7 @@ impl From<&mut str> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_ref_string", since = "1.35.0")]
 impl From<&String> for String {
     #[inline]
@@ -2386,6 +2487,7 @@ impl From<Box<str>> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_str", since = "1.20.0")]
 impl From<String> for Box<str> {
     /// Converts the given `String` to a boxed `str` slice that is owned.
@@ -2406,6 +2508,7 @@ impl From<String> for Box<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_from_cow_str", since = "1.14.0")]
 impl<'a> From<Cow<'a, str>> for String {
     fn from(s: Cow<'a, str>) -> String {
@@ -2413,6 +2516,7 @@ impl<'a> From<Cow<'a, str>> for String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<&'a str> for Cow<'a, str> {
     /// Converts a string slice into a Borrowed variant.
@@ -2431,6 +2535,7 @@ impl<'a> From<&'a str> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<String> for Cow<'a, str> {
     /// Converts a String into an Owned variant.
@@ -2451,6 +2556,7 @@ impl<'a> From<String> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_from_string_ref", since = "1.28.0")]
 impl<'a> From<&'a String> for Cow<'a, str> {
     /// Converts a String reference into a Borrowed variant.
@@ -2470,6 +2576,7 @@ impl<'a> From<&'a String> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_from_iter", since = "1.12.0")]
 impl<'a> FromIterator<char> for Cow<'a, str> {
     fn from_iter<I: IntoIterator<Item = char>>(it: I) -> Cow<'a, str> {
@@ -2477,6 +2584,7 @@ impl<'a> FromIterator<char> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_from_iter", since = "1.12.0")]
 impl<'a, 'b> FromIterator<&'b str> for Cow<'a, str> {
     fn from_iter<I: IntoIterator<Item = &'b str>>(it: I) -> Cow<'a, str> {
@@ -2484,6 +2592,7 @@ impl<'a, 'b> FromIterator<&'b str> for Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_from_iter", since = "1.12.0")]
 impl<'a> FromIterator<String> for Cow<'a, str> {
     fn from_iter<I: IntoIterator<Item = String>>(it: I) -> Cow<'a, str> {
@@ -2512,6 +2621,7 @@ impl From<String> for Vec<u8> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Write for String {
     #[inline]
@@ -2635,6 +2745,7 @@ impl DoubleEndedIterator for Drain<'_> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for Drain<'_> {}
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_char_for_string", since = "1.46.0")]
 impl From<char> for String {
     #[inline]
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 1b7e656cefd..17927f5f5fd 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -12,23 +12,31 @@ use core::fmt;
 use core::hash::{Hash, Hasher};
 use core::hint;
 use core::intrinsics::abort;
+#[cfg(not(no_global_oom_handling))]
 use core::iter;
 use core::marker::{PhantomData, Unpin, Unsize};
-use core::mem::{self, align_of_val_raw, size_of_val};
+#[cfg(not(no_global_oom_handling))]
+use core::mem::size_of_val;
+use core::mem::{self, align_of_val_raw};
 use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
+#[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
 use core::sync::atomic;
 use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
 
-use crate::alloc::{
-    box_free, handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw,
-};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::handle_alloc_error;
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::{box_free, WriteCloneIntoRaw};
+use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::rc::is_dangling;
+#[cfg(not(no_global_oom_handling))]
 use crate::string::String;
+#[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
 #[cfg(test)]
@@ -431,6 +439,7 @@ impl<T> Arc<T> {
     ///
     /// assert_eq!(*five, 5)
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
         unsafe {
@@ -462,6 +471,7 @@ impl<T> Arc<T> {
     /// ```
     ///
     /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> {
         unsafe {
@@ -635,6 +645,7 @@ impl<T> Arc<[T]> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
         unsafe { Arc::from_ptr(Arc::allocate_for_slice(len)) }
@@ -660,6 +671,7 @@ impl<T> Arc<[T]> {
     /// ```
     ///
     /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
         unsafe {
@@ -1072,6 +1084,7 @@ impl<T: ?Sized> Arc<T> {
     ///
     /// The function `mem_to_arcinner` is called with the data pointer
     /// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_layout(
         value_layout: Layout,
         allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
@@ -1120,6 +1133,7 @@ impl<T: ?Sized> Arc<T> {
     }
 
     /// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
         // Allocate for the `ArcInner<T>` using the given value.
         unsafe {
@@ -1131,6 +1145,7 @@ impl<T: ?Sized> Arc<T> {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn from_box(v: Box<T>) -> Arc<T> {
         unsafe {
             let (box_unique, alloc) = Box::into_unique(v);
@@ -1156,6 +1171,7 @@ impl<T: ?Sized> Arc<T> {
 
 impl<T> Arc<[T]> {
     /// Allocates an `ArcInner<[T]>` with the given length.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
         unsafe {
             Self::allocate_for_layout(
@@ -1169,6 +1185,7 @@ impl<T> Arc<[T]> {
     /// Copy elements from slice into newly allocated Arc<\[T\]>
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {
         unsafe {
             let ptr = Self::allocate_for_slice(v.len());
@@ -1182,6 +1199,7 @@ impl<T> Arc<[T]> {
     /// Constructs an `Arc<[T]>` from an iterator known to be of a certain size.
     ///
     /// Behavior is undefined should the size be wrong.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn from_iter_exact(iter: impl iter::Iterator<Item = T>, len: usize) -> Arc<[T]> {
         // Panic guard while cloning T elements.
         // In the event of a panic, elements that have been written
@@ -1229,10 +1247,12 @@ impl<T> Arc<[T]> {
 }
 
 /// Specialization trait used for `From<&[T]>`.
+#[cfg(not(no_global_oom_handling))]
 trait ArcFromSlice<T> {
     fn from_slice(slice: &[T]) -> Self;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
     #[inline]
     default fn from_slice(v: &[T]) -> Self {
@@ -1240,6 +1260,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Copy> ArcFromSlice<T> for Arc<[T]> {
     #[inline]
     fn from_slice(v: &[T]) -> Self {
@@ -1341,6 +1362,7 @@ impl<T: Clone> Arc<T> {
     /// assert_eq!(*data, 8);
     /// assert_eq!(*other_data, 12);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "arc_unique", since = "1.4.0")]
     pub fn make_mut(this: &mut Self) -> &mut T {
@@ -2283,6 +2305,7 @@ impl<T> From<T> for Arc<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: Clone> From<&[T]> for Arc<[T]> {
     /// Allocate a reference-counted slice and fill it by cloning `v`'s items.
@@ -2301,6 +2324,7 @@ impl<T: Clone> From<&[T]> for Arc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<&str> for Arc<str> {
     /// Allocate a reference-counted `str` and copy `v` into it.
@@ -2319,6 +2343,7 @@ impl From<&str> for Arc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<String> for Arc<str> {
     /// Allocate a reference-counted `str` and copy `v` into it.
@@ -2337,6 +2362,7 @@ impl From<String> for Arc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: ?Sized> From<Box<T>> for Arc<T> {
     /// Move a boxed object to a new, reference-counted allocation.
@@ -2355,6 +2381,7 @@ impl<T: ?Sized> From<Box<T>> for Arc<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T> From<Vec<T>> for Arc<[T]> {
     /// Allocate a reference-counted slice and move `v`'s items into it.
@@ -2408,6 +2435,7 @@ impl<T, const N: usize> TryFrom<Arc<[T]>> for Arc<[T; N]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_iter", since = "1.37.0")]
 impl<T> iter::FromIterator<T> for Arc<[T]> {
     /// Takes each element in the `Iterator` and collects it into an `Arc<[T]>`.
@@ -2458,12 +2486,14 @@ trait ToArcSlice<T>: Iterator<Item = T> + Sized {
     fn to_arc_slice(self) -> Arc<[T]>;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: Iterator<Item = T>> ToArcSlice<T> for I {
     default fn to_arc_slice(self) -> Arc<[T]> {
         self.collect::<Vec<T>>().into()
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> for I {
     fn to_arc_slice(self) -> Arc<[T]> {
         // This is the case for a `TrustedLen` iterator.
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 324e894bafd..2e68161d260 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -94,6 +94,7 @@ impl<T, A: Allocator> IntoIter<T, A> {
     /// (&mut into_iter).for_each(core::mem::drop);
     /// unsafe { core::ptr::write(&mut into_iter, Vec::new().into_iter()); }
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     pub(super) fn forget_allocation_drop_remaining(&mut self) {
         let remaining = self.as_raw_mut_slice();
 
@@ -224,6 +225,7 @@ where
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
     #[cfg(not(test))]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 85c9446689e..1c33ff555d6 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -53,12 +53,16 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use core::cmp::{self, Ordering};
+#[cfg(not(no_global_oom_handling))]
+use core::cmp;
+use core::cmp::Ordering;
 use core::convert::TryFrom;
 use core::fmt;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::{arith_offset, assume};
-use core::iter::{self, FromIterator};
+use core::iter;
+#[cfg(not(no_global_oom_handling))]
+use core::iter::FromIterator;
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop, MaybeUninit};
 use core::ops::{self, Index, IndexMut, Range, RangeBounds};
@@ -76,9 +80,11 @@ pub use self::drain_filter::DrainFilter;
 
 mod drain_filter;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_splice", since = "1.21.0")]
 pub use self::splice::Splice;
 
+#[cfg(not(no_global_oom_handling))]
 mod splice;
 
 #[stable(feature = "drain", since = "1.6.0")]
@@ -86,44 +92,60 @@ pub use self::drain::Drain;
 
 mod drain;
 
+#[cfg(not(no_global_oom_handling))]
 mod cow;
 
+#[cfg(not(no_global_oom_handling))]
 pub(crate) use self::into_iter::AsIntoIter;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::into_iter::IntoIter;
 
 mod into_iter;
 
+#[cfg(not(no_global_oom_handling))]
 use self::is_zero::IsZero;
 
 mod is_zero;
 
+#[cfg(not(no_global_oom_handling))]
 mod source_iter_marker;
 
 mod partial_eq;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_from_elem::SpecFromElem;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_from_elem;
 
+#[cfg(not(no_global_oom_handling))]
 use self::set_len_on_drop::SetLenOnDrop;
 
+#[cfg(not(no_global_oom_handling))]
 mod set_len_on_drop;
 
+#[cfg(not(no_global_oom_handling))]
 use self::in_place_drop::InPlaceDrop;
 
+#[cfg(not(no_global_oom_handling))]
 mod in_place_drop;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_from_iter_nested::SpecFromIterNested;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_from_iter_nested;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_from_iter::SpecFromIter;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_from_iter;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_extend::SpecExtend;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_extend;
 
 /// A contiguous growable array type, written as `Vec<T>` and pronounced 'vector'.
@@ -435,6 +457,7 @@ impl<T> Vec<T> {
     /// assert_eq!(vec.len(), 11);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[doc(alias = "malloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -574,6 +597,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert_eq!(vec.len(), 11);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
@@ -774,6 +798,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.reserve(10);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve(&mut self, additional: usize) {
@@ -800,6 +825,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.reserve_exact(10);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve_exact(&mut self, additional: usize) {
@@ -900,6 +926,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.shrink_to_fit();
     /// assert!(vec.capacity() >= 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn shrink_to_fit(&mut self) {
@@ -930,6 +957,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.shrink_to(0);
     /// assert!(vec.capacity() >= 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
@@ -962,6 +990,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// let slice = vec.into_boxed_slice();
     /// assert_eq!(slice.into_vec().capacity(), 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_boxed_slice(mut self) -> Box<[T], A> {
         unsafe {
@@ -1299,6 +1328,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.insert(4, 5);
     /// assert_eq!(vec, [1, 4, 2, 3, 5]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, index: usize, element: T) {
         #[cold]
@@ -1627,6 +1657,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.push(3);
     /// assert_eq!(vec, [1, 2, 3]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push(&mut self, value: T) {
@@ -1680,6 +1711,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
     /// assert_eq!(vec2, []);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "append", since = "1.4.0")]
     pub fn append(&mut self, other: &mut Self) {
@@ -1690,6 +1722,7 @@ impl<T, A: Allocator> Vec<T, A> {
     }
 
     /// Appends elements to `Self` from other buffer.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     unsafe fn append_elements(&mut self, other: *const [T]) {
         let count = unsafe { (*other).len() };
@@ -1827,6 +1860,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert_eq!(vec, [1]);
     /// assert_eq!(vec2, [2, 3]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[must_use = "use `.truncate()` if you don't need the other half"]
     #[stable(feature = "split_off", since = "1.4.0")]
@@ -1891,6 +1925,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.resize_with(4, || { p *= 2; p });
     /// assert_eq!(vec, [2, 4, 8, 16]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_resize_with", since = "1.33.0")]
     pub fn resize_with<F>(&mut self, new_len: usize, f: F)
     where
@@ -1926,6 +1961,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// static_ref[0] += 1;
     /// assert_eq!(static_ref, &[2, 2, 3]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_leak", since = "1.47.0")]
     #[inline]
     pub fn leak<'a>(self) -> &'a mut [T]
@@ -2084,6 +2120,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// vec.resize(2, 0);
     /// assert_eq!(vec, [1, 2]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_resize", since = "1.5.0")]
     pub fn resize(&mut self, new_len: usize, value: T) {
         let len = self.len();
@@ -2114,6 +2151,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// ```
     ///
     /// [`extend`]: Vec::extend
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
     pub fn extend_from_slice(&mut self, other: &[T]) {
         self.spec_extend(other.iter())
@@ -2135,6 +2173,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]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_extend_from_within", since = "1.53.0")]
     pub fn extend_from_within<R>(&mut self, src: R)
     where
@@ -2188,6 +2227,7 @@ impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
 }
 
 impl<T, A: Allocator> Vec<T, A> {
+    #[cfg(not(no_global_oom_handling))]
     /// Extend the vector by `n` values, using the given generator.
     fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
         self.reserve(n);
@@ -2245,12 +2285,14 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> {
 ////////////////////////////////////////////////////////////////////////////////
 
 #[doc(hidden)]
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
     <T as SpecFromElem>::from_elem(elem, n, Global)
 }
 
 #[doc(hidden)]
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "allocator_api", issue = "32838")]
 pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
     <T as SpecFromElem>::from_elem(elem, n, alloc)
@@ -2331,6 +2373,7 @@ impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
     #[cfg(not(test))]
@@ -2397,6 +2440,7 @@ impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> FromIterator<T> for Vec<T> {
     #[inline]
@@ -2467,6 +2511,7 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, A: Allocator> Extend<T> for Vec<T, A> {
     #[inline]
@@ -2488,6 +2533,7 @@ impl<T, A: Allocator> Extend<T> for Vec<T, A> {
 impl<T, A: Allocator> Vec<T, A> {
     // leaf method to which various SpecFrom/SpecExtend implementations delegate when
     // they have no further optimizations to apply
+    #[cfg(not(no_global_oom_handling))]
     fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
         // This is the case for a general iterator.
         //
@@ -2543,6 +2589,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert_eq!(v, &[7, 8, 3]);
     /// assert_eq!(u, &[1, 2]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "vec_splice", since = "1.21.0")]
     pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
@@ -2619,6 +2666,7 @@ impl<T, A: Allocator> Vec<T, A> {
 /// append the entire slice at once.
 ///
 /// [`copy_from_slice`]: slice::copy_from_slice
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_ref", since = "1.2.0")]
 impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
@@ -2713,6 +2761,7 @@ impl<T, A: Allocator> AsMut<[T]> for Vec<T, A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone> From<&[T]> for Vec<T> {
     /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
@@ -2732,6 +2781,7 @@ impl<T: Clone> From<&[T]> for Vec<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_from_mut", since = "1.19.0")]
 impl<T: Clone> From<&mut [T]> for Vec<T> {
     /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
@@ -2813,6 +2863,7 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
 }
 
 // note: test pulls in libstd, which causes errors here
+#[cfg(not(no_global_oom_handling))]
 #[cfg(not(test))]
 #[stable(feature = "box_from_vec", since = "1.20.0")]
 impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
@@ -2831,6 +2882,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<&str> for Vec<u8> {
     /// Allocate a `Vec<u8>` and fill it with a UTF-8 string.
diff --git a/library/alloc/src/vec/partial_eq.rs b/library/alloc/src/vec/partial_eq.rs
index ff90b6caf46..50e14096105 100644
--- a/library/alloc/src/vec/partial_eq.rs
+++ b/library/alloc/src/vec/partial_eq.rs
@@ -1,4 +1,5 @@
 use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::Cow;
 
 use super::Vec;
@@ -26,8 +27,11 @@ __impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A>, #[stable(feature = "partiale
 __impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
 __impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
 __impl_slice_eq1! { [A: Allocator] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
+#[cfg(not(no_global_oom_handling))]
 __impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+#[cfg(not(no_global_oom_handling))]
 __impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+#[cfg(not(no_global_oom_handling))]
 __impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 0a3e5789e8b..f8b16b6f927 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -274,8 +274,7 @@ 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)]
+    #[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn assert_receiver_is_total_eq(&self) {}
@@ -284,7 +283,7 @@ pub trait Eq: PartialEq<Self> {
 /// Derive macro generating an impl of the trait `Eq`.
 #[rustc_builtin_macro]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)]
+#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match, no_coverage)]
 pub macro Eq($item:item) {
     /* compiler built-in */
 }
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/intrinsics.rs b/library/core/src/intrinsics.rs
index 1ba0b23ae5b..0034de9ad1b 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -723,7 +723,7 @@ extern "rust-intrinsic" {
     /// macro, which panics when it is executed, it is *undefined behavior* to
     /// reach code marked with this function.
     ///
-    /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`](crate::hint::unreachable_unchecked).
+    /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`].
     #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
     pub fn unreachable() -> !;
 
@@ -768,13 +768,13 @@ extern "rust-intrinsic" {
     /// More specifically, this is the offset in bytes between successive
     /// items of the same type, including alignment padding.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::size_of`](crate::mem::size_of).
+    /// The stabilized version of this intrinsic is [`core::mem::size_of`].
     #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
     pub fn size_of<T>() -> usize;
 
     /// The minimum alignment of a type.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::align_of`](crate::mem::align_of).
+    /// The stabilized version of this intrinsic is [`core::mem::align_of`].
     #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
     pub fn min_align_of<T>() -> usize;
     /// The preferred alignment of a type.
@@ -790,13 +790,13 @@ extern "rust-intrinsic" {
     pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
     /// The required alignment of the referenced value.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::align_of_val`](crate::mem::align_of_val).
+    /// The stabilized version of this intrinsic is [`core::mem::align_of_val`].
     #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")]
     pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
 
     /// Gets a static string slice containing the name of a type.
     ///
-    /// The stabilized version of this intrinsic is [`core::any::type_name`](crate::any::type_name).
+    /// The stabilized version of this intrinsic is [`core::any::type_name`].
     #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
     pub fn type_name<T: ?Sized>() -> &'static str;
 
@@ -804,7 +804,7 @@ extern "rust-intrinsic" {
     /// function will return the same value for a type regardless of whichever
     /// crate it is invoked in.
     ///
-    /// The stabilized version of this intrinsic is [`core::any::TypeId::of`](crate::any::TypeId::of).
+    /// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
     #[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
@@ -829,7 +829,7 @@ extern "rust-intrinsic" {
 
     /// Gets a reference to a static `Location` indicating where it was called.
     ///
-    /// Consider using [`core::panic::Location::caller`](crate::panic::Location::caller) instead.
+    /// Consider using [`core::panic::Location::caller`] instead.
     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
 
@@ -1158,11 +1158,11 @@ extern "rust-intrinsic" {
 
     /// Performs a volatile load from the `src` pointer.
     ///
-    /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`](crate::ptr::read_volatile).
+    /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`].
     pub fn volatile_load<T>(src: *const T) -> T;
     /// Performs a volatile store to the `dst` pointer.
     ///
-    /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`](crate::ptr::write_volatile).
+    /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`].
     pub fn volatile_store<T>(dst: *mut T, val: T);
 
     /// Performs a volatile load from the `src` pointer
@@ -1703,7 +1703,7 @@ extern "rust-intrinsic" {
     /// Returns the value of the discriminant for the variant in 'v';
     /// if `T` has no discriminant, returns `0`.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::discriminant`](crate::mem::discriminant).
+    /// The stabilized version of this intrinsic is [`core::mem::discriminant`].
     #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
     pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
 
@@ -1773,7 +1773,7 @@ extern "rust-intrinsic" {
     /// [violate memory safety][read-ownership].
     ///
     /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-    /// `0`, the pointers must be non-NULL and properly aligned.
+    /// `0`, the pointers must be non-null and properly aligned.
     ///
     /// [`read`]: crate::ptr::read
     /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
@@ -1857,7 +1857,7 @@ extern "rust-intrinsic" {
     /// [violate memory safety][read-ownership].
     ///
     /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-    /// `0`, the pointers must be non-NULL and properly aligned.
+    /// `0`, the pointers must be non-null and properly aligned.
     ///
     /// [`read`]: crate::ptr::read
     /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
@@ -1928,7 +1928,7 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
 /// invalid value of `T` is undefined behavior.
 ///
 /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointer must be non-NULL and properly aligned.
+/// `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: crate::ptr#safety
 ///
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 0e2c140c367..07bf47b9c6f 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -166,9 +166,14 @@
 #![feature(const_caller_location)]
 #![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
+#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605
 #![feature(int_error_matching)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
+// allow using `core::` in intra-doc links
+#[allow(unused_extern_crates)]
+extern crate self as core;
+
 #[prelude_import]
 #[allow(unused)]
 use prelude::v1::*;
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 4d7d47579ee..10219201a40 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -10,7 +10,7 @@ use crate::ptr;
 ///
 /// The compiler, in general, assumes that a variable is properly initialized
 /// according to the requirements of the variable's type. For example, a variable of
-/// reference type must be aligned and non-NULL. This is an invariant that must
+/// reference type must be aligned and non-null. This is an invariant that must
 /// *always* be upheld, even in unsafe code. As a consequence, zero-initializing a
 /// variable of reference type causes instantaneous [undefined behavior][ub],
 /// no matter whether that reference ever gets used to access memory:
@@ -870,7 +870,7 @@ impl<T> MaybeUninit<T> {
         // SAFETY:
         // * The caller guarantees that all elements of the array are initialized
         // * `MaybeUninit<T>` and T are guaranteed to have the same layout
-        // * MaybeUnint does not drop, so there are no double-frees
+        // * `MaybeUninit` does not drop, so there are no double-frees
         // And thus the conversion is safe
         unsafe {
             intrinsics::assert_inhabited::<[T; N]>();
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index 197b85fba1f..8a06a098882 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -119,7 +119,7 @@ macro_rules! define_bignum {
             pub fn from_small(v: $ty) -> $name {
                 let mut base = [0; $n];
                 base[0] = v;
-                $name { size: 1, base: base }
+                $name { size: 1, base }
             }
 
             /// Makes a bignum from `u64` value.
@@ -131,7 +131,7 @@ macro_rules! define_bignum {
                     v >>= <$ty>::BITS;
                     sz += 1;
                 }
-                $name { size: sz, base: base }
+                $name { size: sz, base }
             }
 
             /// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index b9b2ba9ae61..8348afb2a56 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -66,7 +66,7 @@ impl<T: ?Sized> *const T {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -130,7 +130,7 @@ impl<T: ?Sized> *const T {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -974,7 +974,7 @@ impl<T> *const [T] {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index ad8696ab927..2c324b15a1a 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -149,7 +149,7 @@ mod mut_ptr;
 /// again. [`write()`] can be used to overwrite data without causing it to be
 /// dropped.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -315,7 +315,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///
 /// * Both `x` and `y` must be properly aligned.
 ///
-/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointers must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -394,7 +394,7 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
 ///   beginning at `y` with the same size.
 ///
 /// Note that even if the effectively copied size (`count * size_of::<T>()`) is `0`,
-/// the pointers must be non-NULL and properly aligned.
+/// the pointers must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -540,7 +540,7 @@ const unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
 ///
 /// * `dst` must point to a properly initialized value of type `T`.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -588,7 +588,7 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
 ///
 /// * `src` must point to a properly initialized value of type `T`.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// # Examples
 ///
@@ -713,16 +713,13 @@ pub const unsafe fn read<T>(src: *const T) -> T {
 /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
 /// value and the value at `*src` can [violate memory safety][read-ownership].
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL.
+/// Note that even if `T` has size `0`, the pointer must be non-null.
 ///
 /// [read-ownership]: read#ownership-of-the-returned-value
 /// [valid]: self#safety
 ///
 /// ## On `packed` structs
 ///
-/// It is currently impossible to create raw pointers to unaligned fields
-/// of a packed struct.
-///
 /// Attempting to create a raw pointer to an `unaligned` struct field with
 /// an expression such as `&packed.unaligned as *const FieldType` creates an
 /// intermediate unaligned reference before converting that to a raw pointer.
@@ -731,9 +728,13 @@ pub const unsafe fn read<T>(src: *const T) -> T {
 /// As a result, using `&packed.unaligned as *const FieldType` causes immediate
 /// *undefined behavior* in your program.
 ///
+/// Instead you must use the [`ptr::addr_of!`](addr_of) macro to
+/// create the pointer. You may use that returned pointer together with this
+/// function.
+///
 /// An example of what not to do and how this relates to `read_unaligned` is:
 ///
-/// ```no_run
+/// ```
 /// #[repr(packed, C)]
 /// struct Packed {
 ///     _padding: u8,
@@ -745,24 +746,15 @@ pub const unsafe fn read<T>(src: *const T) -> T {
 ///     unaligned: 0x01020304,
 /// };
 ///
-/// #[allow(unaligned_references)]
-/// let v = unsafe {
-///     // Here we attempt to take the address of a 32-bit integer which is not aligned.
-///     let unaligned =
-///         // A temporary unaligned reference is created here which results in
-///         // undefined behavior regardless of whether the reference is used or not.
-///         &packed.unaligned
-///         // Casting to a raw pointer doesn't help; the mistake already happened.
-///         as *const u32;
+/// // Take the address of a 32-bit integer which is not aligned.
+/// // In contrast to `&packed.unaligned as *const _`, this has no undefined behavior.
+/// let unaligned = std::ptr::addr_of!(packed.unaligned);
 ///
-///     let v = std::ptr::read_unaligned(unaligned);
-///
-///     v
-/// };
+/// let v = unsafe { std::ptr::read_unaligned(unaligned) };
+/// assert_eq!(v, 0x01020304);
 /// ```
 ///
 /// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
-// FIXME: Update docs based on outcome of RFC #2582 and friends.
 ///
 /// # Examples
 ///
@@ -818,7 +810,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
 ///   case.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -910,15 +902,12 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
 ///
 /// * `dst` must be [valid] for writes.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL.
+/// Note that even if `T` has size `0`, the pointer must be non-null.
 ///
 /// [valid]: self#safety
 ///
 /// ## On `packed` structs
 ///
-/// It is currently impossible to create raw pointers to unaligned fields
-/// of a packed struct.
-///
 /// Attempting to create a raw pointer to an `unaligned` struct field with
 /// an expression such as `&packed.unaligned as *const FieldType` creates an
 /// intermediate unaligned reference before converting that to a raw pointer.
@@ -927,36 +916,32 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
 /// As a result, using `&packed.unaligned as *const FieldType` causes immediate
 /// *undefined behavior* in your program.
 ///
-/// An example of what not to do and how this relates to `write_unaligned` is:
+/// Instead you must use the [`ptr::addr_of_mut!`](addr_of_mut)
+/// macro to create the pointer. You may use that returned pointer together with
+/// this function.
+///
+/// An example of how to do it and how this relates to `write_unaligned` is:
 ///
-/// ```no_run
+/// ```
 /// #[repr(packed, C)]
 /// struct Packed {
 ///     _padding: u8,
 ///     unaligned: u32,
 /// }
 ///
-/// let v = 0x01020304;
 /// let mut packed: Packed = unsafe { std::mem::zeroed() };
 ///
-/// #[allow(unaligned_references)]
-/// let v = unsafe {
-///     // Here we attempt to take the address of a 32-bit integer which is not aligned.
-///     let unaligned =
-///         // A temporary unaligned reference is created here which results in
-///         // undefined behavior regardless of whether the reference is used or not.
-///         &mut packed.unaligned
-///         // Casting to a raw pointer doesn't help; the mistake already happened.
-///         as *mut u32;
+/// // Take the address of a 32-bit integer which is not aligned.
+/// // In contrast to `&packed.unaligned as *mut _`, this has no undefined behavior.
+/// let unaligned = std::ptr::addr_of_mut!(packed.unaligned);
 ///
-///     std::ptr::write_unaligned(unaligned, v);
+/// unsafe { std::ptr::write_unaligned(unaligned, 42) };
 ///
-///     v
-/// };
+/// assert_eq!({packed.unaligned}, 42); // `{...}` forces copying the field instead of creating a reference.
 /// ```
 ///
-/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
-// FIXME: Update docs based on outcome of RFC #2582 and friends.
+/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however
+/// (as can be seen in the `assert_eq!` above).
 ///
 /// # Examples
 ///
@@ -1024,7 +1009,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 /// However, storing non-[`Copy`] types in volatile memory is almost certainly
 /// incorrect.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 /// [read-ownership]: read#ownership-of-the-returned-value
@@ -1094,7 +1079,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// * `dst` must be properly aligned.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -1496,7 +1481,7 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
 ///
 /// Note, however, that the `expr` in `addr_of!(expr)` is still subject to all
 /// the usual rules. In particular, `addr_of!(*ptr::null())` is Undefined
-/// Behavior because it dereferences a NULL pointer.
+/// Behavior because it dereferences a null pointer.
 ///
 /// # Example
 ///
@@ -1536,7 +1521,7 @@ pub macro addr_of($place:expr) {
 ///
 /// Note, however, that the `expr` in `addr_of_mut!(expr)` is still subject to all
 /// the usual rules. In particular, `addr_of_mut!(*ptr::null_mut())` is Undefined
-/// Behavior because it dereferences a NULL pointer.
+/// Behavior because it dereferences a null pointer.
 ///
 /// # Examples
 ///
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 55c019c51d5..292ac3e3f7f 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -68,7 +68,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -135,7 +135,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -314,7 +314,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -380,7 +380,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -1237,7 +1237,7 @@ impl<T> *mut [T] {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
@@ -1288,7 +1288,7 @@ impl<T> *mut [T] {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::<T>()`
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index e525f616043..1c65518af04 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -519,7 +519,7 @@ impl<T> NonNull<[T]> {
         I: SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
-        // As a consequence, the resulting pointer cannot be NULL.
+        // As a consequence, the resulting pointer cannot be null.
         unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
     }
 }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index ec28cdd1ba0..0923175414e 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1948,8 +1948,9 @@ impl<T> [T] {
     /// assert!(!v.contains(&50));
     /// ```
     ///
-    /// If you do not have an `&T`, but just an `&U` such that `T: Borrow<U>`
-    /// (e.g. `String: Borrow<str>`), you can use `iter().any`:
+    /// If you do not have a `&T`, but some other value that you can compare
+    /// with one (for example, `String` implements `PartialEq<str>`), you can
+    /// use `iter().any`:
     ///
     /// ```
     /// let v = [String::from("hello"), String::from("world")]; // slice of `String`
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index bfea39e3211..489b7224403 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -518,13 +518,11 @@ impl Duration {
         if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
             let nanos = if self.nanos >= rhs.nanos {
                 self.nanos - rhs.nanos
+            } else if let Some(sub_secs) = secs.checked_sub(1) {
+                secs = sub_secs;
+                self.nanos + NANOS_PER_SEC - rhs.nanos
             } else {
-                if let Some(sub_secs) = secs.checked_sub(1) {
-                    secs = sub_secs;
-                    self.nanos + NANOS_PER_SEC - rhs.nanos
-                } else {
-                    return None;
-                }
+                return None;
             };
             debug_assert!(nanos < NANOS_PER_SEC);
             Some(Duration { secs, nanos })
diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs
index 5597bbb93d2..58028d40576 100644
--- a/library/panic_unwind/src/seh.rs
+++ b/library/panic_unwind/src/seh.rs
@@ -316,7 +316,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
 }
 
 pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
-    // A NULL payload here means that we got here from the catch (...) of
+    // A null payload here means that we got here from the catch (...) of
     // __rust_try. This happens when a non-Rust foreign exception is caught.
     if payload.is_null() {
         super::__rust_foreign_exception();
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index bdf559847cc..a1f52a9c2e8 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -962,7 +962,6 @@ where
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::HashMap;
     ///
     /// let mut map = HashMap::new();
@@ -973,7 +972,7 @@ where
     /// let vec: Vec<&str> = map.into_keys().collect();
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_keys(self) -> IntoKeys<K, V> {
         IntoKeys { inner: self.into_iter() }
     }
@@ -985,7 +984,6 @@ where
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::HashMap;
     ///
     /// let mut map = HashMap::new();
@@ -996,7 +994,7 @@ where
     /// let vec: Vec<i32> = map.into_values().collect();
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_values(self) -> IntoValues<K, V> {
         IntoValues { inner: self.into_iter() }
     }
@@ -1405,15 +1403,13 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 /// # Example
 ///
 /// ```
-/// #![feature(map_into_keys_values)]
-///
 /// use std::collections::HashMap;
 ///
 /// let mut map = HashMap::new();
 /// map.insert("a", 1);
 /// let iter_keys = map.into_keys();
 /// ```
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
@@ -1428,15 +1424,13 @@ pub struct IntoKeys<K, V> {
 /// # Example
 ///
 /// ```
-/// #![feature(map_into_keys_values)]
-///
 /// use std::collections::HashMap;
 ///
 /// let mut map = HashMap::new();
 /// map.insert("a", 1);
 /// let iter_keys = map.into_values();
 /// ```
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
@@ -2137,7 +2131,7 @@ impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoKeys<K, V> {
     type Item = K;
 
@@ -2150,24 +2144,24 @@ impl<K, V> Iterator for IntoKeys<K, V> {
         self.inner.size_hint()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoKeys<K, V> {}
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K: Debug, V> fmt::Debug for IntoKeys<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoValues<K, V> {
     type Item = V;
 
@@ -2180,17 +2174,17 @@ impl<K, V> Iterator for IntoValues<K, V> {
         self.inner.size_hint()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoValues<K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoValues<K, V> {}
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V: Debug> fmt::Debug for IntoValues<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 821e7d4cfe7..11d052dae9e 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -61,6 +61,7 @@ pub fn current_dir() -> io::Result<PathBuf> {
 /// assert!(env::set_current_dir(&root).is_ok());
 /// println!("Successfully changed working directory to {}!", root.display());
 /// ```
+#[doc(alias = "chdir")]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
     os_imp::chdir(path.as_ref())
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index ed4950c57a6..2f9845d7536 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -498,7 +498,7 @@ impl CString {
     /// Failure to call [`CString::from_raw`] will lead to a memory leak.
     ///
     /// The C side must **not** modify the length of the string (by writing a
-    /// `NULL` somewhere inside the string or removing the final one) before
+    /// `null` somewhere inside the string or removing the final one) before
     /// it makes it back into Rust using [`CString::from_raw`]. See the safety section
     /// in [`CString::from_raw`].
     ///
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index 80f98bbbad3..ef2769d431f 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -4,6 +4,7 @@ use crate::io::{
     self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
 };
 use crate::mem;
+use crate::ptr;
 
 /// Wraps a writer and buffers its output.
 ///
@@ -68,6 +69,10 @@ use crate::mem;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
     inner: Option<W>,
+    // The buffer. Avoid using this like a normal `Vec` in common code paths.
+    // That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
+    // methods that require bounds checking or the like. This makes an enormous
+    // difference to performance (we may want to stop using a `Vec` entirely).
     buf: Vec<u8>,
     // #30888: If the inner writer panics in a call to write, we don't want to
     // write the buffered data a second time in BufWriter's destructor. This
@@ -181,9 +186,14 @@ impl<W: Write> BufWriter<W> {
     /// data. Writes as much as possible without exceeding capacity. Returns
     /// the number of bytes written.
     pub(super) fn write_to_buf(&mut self, buf: &[u8]) -> usize {
-        let available = self.buf.capacity() - self.buf.len();
+        let available = self.spare_capacity();
         let amt_to_buffer = available.min(buf.len());
-        self.buf.extend_from_slice(&buf[..amt_to_buffer]);
+
+        // SAFETY: `amt_to_buffer` is <= buffer's spare capacity by construction.
+        unsafe {
+            self.write_to_buffer_unchecked(&buf[..amt_to_buffer]);
+        }
+
         amt_to_buffer
     }
 
@@ -331,6 +341,103 @@ impl<W: Write> BufWriter<W> {
         let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
         (self.inner.take().unwrap(), buf)
     }
+
+    // Ensure this function does not get inlined into `write`, so that it
+    // remains inlineable and its common path remains as short as possible.
+    // If this function ends up being called frequently relative to `write`,
+    // it's likely a sign that the client is using an improperly sized buffer
+    // or their write patterns are somewhat pathological.
+    #[cold]
+    #[inline(never)]
+    fn write_cold(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if buf.len() > self.spare_capacity() {
+            self.flush_buf()?;
+        }
+
+        // Why not len > capacity? To avoid a needless trip through the buffer when the input
+        // exactly fills it. We'd just need to flush it to the underlying writer anyway.
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write(buf);
+            self.panicked = false;
+            r
+        } else {
+            // Write to the buffer. In this case, we write to the buffer even if it fills it
+            // exactly. Doing otherwise would mean flushing the buffer, then writing this
+            // input to the inner writer, which in many cases would be a worse strategy.
+
+            // SAFETY: There was either enough spare capacity already, or there wasn't and we
+            // flushed the buffer to ensure that there is. In the latter case, we know that there
+            // is because flushing ensured that our entire buffer is spare capacity, and we entered
+            // this block because the input buffer length is less than that capacity. In either
+            // case, it's safe to write the input buffer to our buffer.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
+            Ok(buf.len())
+        }
+    }
+
+    // Ensure this function does not get inlined into `write_all`, so that it
+    // remains inlineable and its common path remains as short as possible.
+    // If this function ends up being called frequently relative to `write_all`,
+    // it's likely a sign that the client is using an improperly sized buffer
+    // or their write patterns are somewhat pathological.
+    #[cold]
+    #[inline(never)]
+    fn write_all_cold(&mut self, buf: &[u8]) -> io::Result<()> {
+        // Normally, `write_all` just calls `write` in a loop. We can do better
+        // by calling `self.get_mut().write_all()` directly, which avoids
+        // round trips through the buffer in the event of a series of partial
+        // writes in some circumstances.
+
+        if buf.len() > self.spare_capacity() {
+            self.flush_buf()?;
+        }
+
+        // Why not len > capacity? To avoid a needless trip through the buffer when the input
+        // exactly fills it. We'd just need to flush it to the underlying writer anyway.
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write_all(buf);
+            self.panicked = false;
+            r
+        } else {
+            // Write to the buffer. In this case, we write to the buffer even if it fills it
+            // exactly. Doing otherwise would mean flushing the buffer, then writing this
+            // input to the inner writer, which in many cases would be a worse strategy.
+
+            // SAFETY: There was either enough spare capacity already, or there wasn't and we
+            // flushed the buffer to ensure that there is. In the latter case, we know that there
+            // is because flushing ensured that our entire buffer is spare capacity, and we entered
+            // this block because the input buffer length is less than that capacity. In either
+            // case, it's safe to write the input buffer to our buffer.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
+            Ok(())
+        }
+    }
+
+    // SAFETY: Requires `buf.len() <= self.buf.capacity() - self.buf.len()`,
+    // i.e., that input buffer length is less than or equal to spare capacity.
+    #[inline]
+    unsafe fn write_to_buffer_unchecked(&mut self, buf: &[u8]) {
+        debug_assert!(buf.len() <= self.spare_capacity());
+        let old_len = self.buf.len();
+        let buf_len = buf.len();
+        let src = buf.as_ptr();
+        let dst = self.buf.as_mut_ptr().add(old_len);
+        ptr::copy_nonoverlapping(src, dst, buf_len);
+        self.buf.set_len(old_len + buf_len);
+    }
+
+    #[inline]
+    fn spare_capacity(&self) -> usize {
+        self.buf.capacity() - self.buf.len()
+    }
 }
 
 #[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")]
@@ -402,63 +509,82 @@ impl fmt::Debug for WriterPanicked {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<W: Write> Write for BufWriter<W> {
+    #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
+        // Use < instead of <= to avoid a needless trip through the buffer in some cases.
+        // See `write_cold` for details.
+        if buf.len() < self.spare_capacity() {
+            // SAFETY: safe by above conditional.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
             Ok(buf.len())
+        } else {
+            self.write_cold(buf)
         }
     }
 
+    #[inline]
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        // Normally, `write_all` just calls `write` in a loop. We can do better
-        // by calling `self.get_mut().write_all()` directly, which avoids
-        // round trips through the buffer in the event of a series of partial
-        // writes in some circumstances.
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write_all(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
+        // Use < instead of <= to avoid a needless trip through the buffer in some cases.
+        // See `write_all_cold` for details.
+        if buf.len() < self.spare_capacity() {
+            // SAFETY: safe by above conditional.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
             Ok(())
+        } else {
+            self.write_all_cold(buf)
         }
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        // FIXME: Consider applying `#[inline]` / `#[inline(never)]` optimizations already applied
+        // to `write` and `write_all`. The performance benefits can be significant. See #79930.
         if self.get_ref().is_write_vectored() {
-            let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
-            if self.buf.len() + total_len > self.buf.capacity() {
+            // We have to handle the possibility that the total length of the buffers overflows
+            // `usize` (even though this can only happen if multiple `IoSlice`s reference the
+            // same underlying buffer, as otherwise the buffers wouldn't fit in memory). If the
+            // computation overflows, then surely the input cannot fit in our buffer, so we forward
+            // to the inner writer's `write_vectored` method to let it handle it appropriately.
+            let saturated_total_len =
+                bufs.iter().fold(0usize, |acc, b| acc.saturating_add(b.len()));
+
+            if saturated_total_len > self.spare_capacity() {
+                // Flush if the total length of the input exceeds our buffer's spare capacity.
+                // If we would have overflowed, this condition also holds, and we need to flush.
                 self.flush_buf()?;
             }
-            if total_len >= self.buf.capacity() {
+
+            if saturated_total_len >= self.buf.capacity() {
+                // Forward to our inner writer if the total length of the input is greater than or
+                // equal to our buffer capacity. If we would have overflowed, this condition also
+                // holds, and we punt to the inner writer.
                 self.panicked = true;
                 let r = self.get_mut().write_vectored(bufs);
                 self.panicked = false;
                 r
             } else {
-                bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
-                Ok(total_len)
+                // `saturated_total_len < self.buf.capacity()` implies that we did not saturate.
+
+                // SAFETY: We checked whether or not the spare capacity was large enough above. If
+                // it was, then we're safe already. If it wasn't, we flushed, making sufficient
+                // room for any input <= the buffer size, which includes this input.
+                unsafe {
+                    bufs.iter().for_each(|b| self.write_to_buffer_unchecked(b));
+                };
+
+                Ok(saturated_total_len)
             }
         } else {
             let mut iter = bufs.iter();
             let mut total_written = if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) {
                 // This is the first non-empty slice to write, so if it does
                 // not fit in the buffer, we still get to flush and proceed.
-                if self.buf.len() + buf.len() > self.buf.capacity() {
+                if buf.len() > self.spare_capacity() {
                     self.flush_buf()?;
                 }
                 if buf.len() >= self.buf.capacity() {
@@ -469,7 +595,13 @@ impl<W: Write> Write for BufWriter<W> {
                     self.panicked = false;
                     return r;
                 } else {
-                    self.buf.extend_from_slice(buf);
+                    // SAFETY: We checked whether or not the spare capacity was large enough above.
+                    // If it was, then we're safe already. If it wasn't, we flushed, making
+                    // sufficient room for any input <= the buffer size, which includes this input.
+                    unsafe {
+                        self.write_to_buffer_unchecked(buf);
+                    }
+
                     buf.len()
                 }
             } else {
@@ -477,11 +609,18 @@ impl<W: Write> Write for BufWriter<W> {
             };
             debug_assert!(total_written != 0);
             for buf in iter {
-                if self.buf.len() + buf.len() > self.buf.capacity() {
-                    break;
-                } else {
-                    self.buf.extend_from_slice(buf);
+                if buf.len() <= self.spare_capacity() {
+                    // SAFETY: safe by above conditional.
+                    unsafe {
+                        self.write_to_buffer_unchecked(buf);
+                    }
+
+                    // This cannot overflow `usize`. If we are here, we've written all of the bytes
+                    // so far to our buffer, and we've ensured that we never exceed the buffer's
+                    // capacity. Therefore, `total_written` <= `self.buf.capacity()` <= `usize::MAX`.
                     total_written += buf.len();
+                } else {
+                    break;
                 }
             }
             Ok(total_written)
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 9bed12bf2ae..56e6f08268c 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -186,6 +186,11 @@ pub enum ErrorKind {
     /// This means that the operation can never succeed.
     #[stable(feature = "unsupported_error", since = "1.53.0")]
     Unsupported,
+
+    /// An operation could not be completed, because it failed
+    /// to allocate enough memory.
+    #[stable(feature = "out_of_memory_error", since = "1.54.0")]
+    OutOfMemory,
 }
 
 impl ErrorKind {
@@ -210,6 +215,7 @@ impl ErrorKind {
             ErrorKind::Other => "other os error",
             ErrorKind::UnexpectedEof => "unexpected end of file",
             ErrorKind::Unsupported => "unsupported",
+            ErrorKind::OutOfMemory => "out of memory",
         }
     }
 }
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index b9af5992dff..18297139b7b 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -159,7 +159,7 @@ impl UdpSocket {
     /// This will return an error when the IP version of the local socket
     /// does not match that returned from [`ToSocketAddrs`].
     ///
-    /// See issue #34202 for more details.
+    /// See [Issue #34202] for more details.
     ///
     /// # Examples
     ///
@@ -169,6 +169,8 @@ impl UdpSocket {
     /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
     /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data");
     /// ```
+    ///
+    /// [Issue #34202]: https://github.com/rust-lang/rust/issues/34202
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
         match addr.to_socket_addrs()?.next() {
diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/os/fortanix_sgx/arch.rs
index b0170e67446..b0170e67446 100644
--- a/library/std/src/sys/sgx/ext/arch.rs
+++ b/library/std/src/os/fortanix_sgx/arch.rs
diff --git a/library/std/src/sys/sgx/ext/ffi.rs b/library/std/src/os/fortanix_sgx/ffi.rs
index 63fc5ff2866..63fc5ff2866 100644
--- a/library/std/src/sys/sgx/ext/ffi.rs
+++ b/library/std/src/os/fortanix_sgx/ffi.rs
diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/os/fortanix_sgx/io.rs
index 7223ade6815..7223ade6815 100644
--- a/library/std/src/sys/sgx/ext/io.rs
+++ b/library/std/src/os/fortanix_sgx/io.rs
diff --git a/library/std/src/os/fortanix_sgx/mod.rs b/library/std/src/os/fortanix_sgx/mod.rs
index 69923268e57..a40dabe190a 100644
--- a/library/std/src/os/fortanix_sgx/mod.rs
+++ b/library/std/src/os/fortanix_sgx/mod.rs
@@ -3,7 +3,7 @@
 //! This includes functions to deal with memory isolation, usercalls, and the
 //! SGX instruction set.
 
-#![deny(missing_docs, missing_debug_implementations)]
+#![deny(missing_docs)]
 #![unstable(feature = "sgx_platform", issue = "56975")]
 
 /// Low-level interfaces to usercalls. See the [ABI documentation] for more
@@ -43,7 +43,9 @@ pub mod mem {
     pub use crate::sys::abi::mem::*;
 }
 
-pub use crate::sys::ext::{arch, ffi, io};
+pub mod arch;
+pub mod ffi;
+pub mod io;
 
 /// Functions for querying thread-related information.
 pub mod thread {
diff --git a/library/std/src/sys/hermit/ext/ffi.rs b/library/std/src/os/hermit/ffi.rs
index 07b59a02556..07b59a02556 100644
--- a/library/std/src/sys/hermit/ext/ffi.rs
+++ b/library/std/src/os/hermit/ffi.rs
diff --git a/library/std/src/sys/hermit/ext/mod.rs b/library/std/src/os/hermit/mod.rs
index ea87d0ad2c9..4657b545a1b 100644
--- a/library/std/src/sys/hermit/ext/mod.rs
+++ b/library/std/src/os/hermit/mod.rs
@@ -1,5 +1,4 @@
 #![stable(feature = "rust1", since = "1.0.0")]
-#![allow(missing_docs)]
 
 pub mod ffi;
 
diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs
index f179a524336..94438defc22 100644
--- a/library/std/src/os/linux/mod.rs
+++ b/library/std/src/os/linux/mod.rs
@@ -1,6 +1,7 @@
 //! Linux-specific definitions.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
+#![doc(cfg(target_os = "linux"))]
 
 pub mod fs;
 pub mod raw;
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
index 525102212c4..5b68a7e1262 100644
--- a/library/std/src/os/linux/raw.rs
+++ b/library/std/src/os/linux/raw.rs
@@ -9,7 +9,6 @@
               definitions"
 )]
 #![allow(deprecated)]
-#![allow(missing_debug_implementations)]
 
 use crate::os::raw::c_ulong;
 
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index b95511e43d8..07e29ebf368 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -3,78 +3,119 @@
 #![stable(feature = "os", since = "1.0.0")]
 #![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
 
-// When documenting libstd we want to show unix/windows/linux/wasi modules as these are the "main
-// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set.
-// This should help show platform-specific functionality in a hopefully cross-platform way in the
-// documentation.
-// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make
-// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038
+pub mod raw;
 
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::unix_ext as unix;
+// The code below could be written clearer using `cfg_if!`. However, the items below are
+// publicly exported by `std` and external tools can have trouble analysing them because of the use
+// of a macro that is not vendored by Rust and included in the toolchain.
+// See https://github.com/rust-analyzer/rust-analyzer/issues/6038.
 
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::windows_ext as windows;
+#[cfg(all(
+    doc,
+    not(any(
+        all(target_arch = "wasm32", not(target_os = "wasi")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    ))
+))]
+#[path = "."]
+mod doc {
+    // When documenting std we want to show the `unix`, `windows`, `linux` and `wasi`
+    // modules as these are the "main modules" that are used across platforms,
+    // so these modules are enabled when `cfg(doc)` is set.
+    // This should help show platform-specific functionality in a hopefully cross-platform
+    // way in the documentation.
 
-#[cfg(doc)]
-#[doc(cfg(target_os = "linux"))]
-pub mod linux;
+    pub mod unix;
 
-#[cfg(doc)]
-#[stable(feature = "wasi_ext_doc", since = "1.35.0")]
-pub use crate::sys::wasi_ext as wasi;
+    pub mod linux;
 
-// If we're not documenting libstd then we just expose the main modules as we otherwise would.
+    pub mod wasi;
 
-#[cfg(not(doc))]
-#[cfg(any(unix, target_os = "hermit"))]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::ext as unix;
+    pub mod windows;
+}
+#[cfg(all(
+    doc,
+    any(
+        all(target_arch = "wasm32", not(target_os = "wasi")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    )
+))]
+mod doc {
+    // On certain platforms right now the "main modules" modules that are
+    // documented don't compile (missing things in `libc` which is empty),
+    // so just omit them with an empty module.
 
-#[cfg(not(doc))]
-#[cfg(windows)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::ext as windows;
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod unix {}
 
-#[cfg(not(doc))]
-#[cfg(any(target_os = "linux", target_os = "l4re"))]
-pub mod linux;
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod linux {}
+
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod wasi {}
+
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod windows {}
+}
+#[cfg(doc)]
+#[stable(feature = "os", since = "1.0.0")]
+pub use doc::*;
 
 #[cfg(not(doc))]
-#[cfg(target_os = "wasi")]
-pub mod wasi;
-
-#[cfg(target_os = "android")]
-pub mod android;
-#[cfg(target_os = "dragonfly")]
-pub mod dragonfly;
-#[cfg(target_os = "emscripten")]
-pub mod emscripten;
-#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-pub mod fortanix_sgx;
-#[cfg(target_os = "freebsd")]
-pub mod freebsd;
-#[cfg(target_os = "fuchsia")]
-pub mod fuchsia;
-#[cfg(target_os = "haiku")]
-pub mod haiku;
-#[cfg(target_os = "illumos")]
-pub mod illumos;
-#[cfg(target_os = "ios")]
-pub mod ios;
-#[cfg(target_os = "macos")]
-pub mod macos;
-#[cfg(target_os = "netbsd")]
-pub mod netbsd;
-#[cfg(target_os = "openbsd")]
-pub mod openbsd;
-#[cfg(target_os = "redox")]
-pub mod redox;
-#[cfg(target_os = "solaris")]
-pub mod solaris;
-#[cfg(target_os = "vxworks")]
-pub mod vxworks;
+#[path = "."]
+mod imp {
+    // If we're not documenting std then we only expose modules appropriate for the
+    // current platform.
 
-pub mod raw;
+    #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
+    pub mod fortanix_sgx;
+
+    #[cfg(target_os = "hermit")]
+    #[path = "hermit/mod.rs"]
+    pub mod unix;
+
+    #[cfg(target_os = "android")]
+    pub mod android;
+    #[cfg(target_os = "dragonfly")]
+    pub mod dragonfly;
+    #[cfg(target_os = "emscripten")]
+    pub mod emscripten;
+    #[cfg(target_os = "freebsd")]
+    pub mod freebsd;
+    #[cfg(target_os = "fuchsia")]
+    pub mod fuchsia;
+    #[cfg(target_os = "haiku")]
+    pub mod haiku;
+    #[cfg(target_os = "illumos")]
+    pub mod illumos;
+    #[cfg(target_os = "ios")]
+    pub mod ios;
+    #[cfg(target_os = "l4re")]
+    pub mod linux;
+    #[cfg(target_os = "linux")]
+    pub mod linux;
+    #[cfg(target_os = "macos")]
+    pub mod macos;
+    #[cfg(target_os = "netbsd")]
+    pub mod netbsd;
+    #[cfg(target_os = "openbsd")]
+    pub mod openbsd;
+    #[cfg(target_os = "redox")]
+    pub mod redox;
+    #[cfg(target_os = "solaris")]
+    pub mod solaris;
+    #[cfg(unix)]
+    pub mod unix;
+
+    #[cfg(target_os = "vxworks")]
+    pub mod vxworks;
+
+    #[cfg(target_os = "wasi")]
+    pub mod wasi;
+
+    #[cfg(windows)]
+    pub mod windows;
+}
+#[cfg(not(doc))]
+#[stable(feature = "os", since = "1.0.0")]
+pub use imp::*;
diff --git a/library/std/src/os/redox/raw.rs b/library/std/src/os/redox/raw.rs
index abe6dfc6b0c..9a6b99684c5 100644
--- a/library/std/src/os/redox/raw.rs
+++ b/library/std/src/os/redox/raw.rs
@@ -9,7 +9,6 @@
               definitions"
 )]
 #![allow(deprecated)]
-#![allow(missing_debug_implementations)]
 
 use crate::os::raw::{c_char, c_int, c_long, c_ulong, c_void};
 
diff --git a/library/std/src/sys/unix/ext/ffi.rs b/library/std/src/os/unix/ffi.rs
index 123f85deaf9..123f85deaf9 100644
--- a/library/std/src/sys/unix/ext/ffi.rs
+++ b/library/std/src/os/unix/ffi.rs
diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/os/unix/fs.rs
index 9cf51be2836..9cf51be2836 100644
--- a/library/std/src/sys/unix/ext/fs.rs
+++ b/library/std/src/os/unix/fs.rs
diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/os/unix/io.rs
index 07c30bfa9ed..07c30bfa9ed 100644
--- a/library/std/src/sys/unix/ext/io.rs
+++ b/library/std/src/os/unix/io.rs
diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/os/unix/mod.rs
index 735bf35a3ce..6fc1c89a2ba 100644
--- a/library/std/src/sys/unix/ext/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -27,44 +27,43 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![doc(cfg(unix))]
-#![allow(missing_docs)]
 
-cfg_if::cfg_if! {
-    if #[cfg(doc)] {
-        // Use linux as the default platform when documenting on other platforms like Windows
-        use crate::os::linux as platform;
-    } else {
-        #[cfg(target_os = "android")]
-        use crate::os::android as platform;
-        #[cfg(target_os = "dragonfly")]
-        use crate::os::dragonfly as platform;
-        #[cfg(target_os = "emscripten")]
-        use crate::os::emscripten as platform;
-        #[cfg(target_os = "freebsd")]
-        use crate::os::freebsd as platform;
-        #[cfg(target_os = "fuchsia")]
-        use crate::os::fuchsia as platform;
-        #[cfg(target_os = "haiku")]
-        use crate::os::haiku as platform;
-        #[cfg(target_os = "illumos")]
-        use crate::os::illumos as platform;
-        #[cfg(target_os = "ios")]
-        use crate::os::ios as platform;
-        #[cfg(any(target_os = "linux", target_os = "l4re"))]
-        use crate::os::linux as platform;
-        #[cfg(target_os = "macos")]
-        use crate::os::macos as platform;
-        #[cfg(target_os = "netbsd")]
-        use crate::os::netbsd as platform;
-        #[cfg(target_os = "openbsd")]
-        use crate::os::openbsd as platform;
-        #[cfg(target_os = "redox")]
-        use crate::os::redox as platform;
-        #[cfg(target_os = "solaris")]
-        use crate::os::solaris as platform;
-        #[cfg(target_os = "vxworks")]
-        use crate::os::vxworks as platform;
-    }
+// Use linux as the default platform when documenting on other platforms like Windows
+#[cfg(doc)]
+use crate::os::linux as platform;
+
+#[cfg(not(doc))]
+mod platform {
+    #[cfg(target_os = "android")]
+    pub use crate::os::android::*;
+    #[cfg(target_os = "dragonfly")]
+    pub use crate::os::dragonfly::*;
+    #[cfg(target_os = "emscripten")]
+    pub use crate::os::emscripten::*;
+    #[cfg(target_os = "freebsd")]
+    pub use crate::os::freebsd::*;
+    #[cfg(target_os = "fuchsia")]
+    pub use crate::os::fuchsia::*;
+    #[cfg(target_os = "haiku")]
+    pub use crate::os::haiku::*;
+    #[cfg(target_os = "illumos")]
+    pub use crate::os::illumos::*;
+    #[cfg(target_os = "ios")]
+    pub use crate::os::ios::*;
+    #[cfg(any(target_os = "linux", target_os = "l4re"))]
+    pub use crate::os::linux::*;
+    #[cfg(target_os = "macos")]
+    pub use crate::os::macos::*;
+    #[cfg(target_os = "netbsd")]
+    pub use crate::os::netbsd::*;
+    #[cfg(target_os = "openbsd")]
+    pub use crate::os::openbsd::*;
+    #[cfg(target_os = "redox")]
+    pub use crate::os::redox::*;
+    #[cfg(target_os = "solaris")]
+    pub use crate::os::solaris::*;
+    #[cfg(target_os = "vxworks")]
+    pub use crate::os::vxworks::*;
 }
 
 pub mod ffi;
diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index 459f3590e64..459f3590e64 100644
--- a/library/std/src/sys/unix/ext/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 011ae643f87..15ce7056fea 100644
--- a/library/std/src/sys/unix/ext/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -49,7 +49,7 @@ pub(super) fn recv_vectored_with_ancillary_from(
                 msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
             }
         }
-        // macos requires that the control pointer is NULL when the len is 0.
+        // macos requires that the control pointer is null when the len is 0.
         if msg.msg_controllen > 0 {
             msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
         }
@@ -97,7 +97,7 @@ pub(super) fn send_vectored_with_ancillary_to(
                 msg.msg_controllen = ancillary.length as libc::socklen_t;
             }
         }
-        // macos requires that the control pointer is NULL when the len is 0.
+        // macos requires that the control pointer is null when the len is 0.
         if msg.msg_controllen > 0 {
             msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
         }
diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index 9e39f70f68e..9e39f70f68e 100644
--- a/library/std/src/sys/unix/ext/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index bdd08fe8380..bdd08fe8380 100644
--- a/library/std/src/sys/unix/ext/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/os/unix/net/mod.rs
index 3088ffb5e5c..3088ffb5e5c 100644
--- a/library/std/src/sys/unix/ext/net/mod.rs
+++ b/library/std/src/os/unix/net/mod.rs
diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/os/unix/net/raw_fd.rs
index b3f12844101..b3f12844101 100644
--- a/library/std/src/sys/unix/ext/net/raw_fd.rs
+++ b/library/std/src/os/unix/net/raw_fd.rs
diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index a6f6e091305..a6f6e091305 100644
--- a/library/std/src/sys/unix/ext/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index bd9b6dd727b..bd9b6dd727b 100644
--- a/library/std/src/sys/unix/ext/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/os/unix/process.rs
index 355855bcd10..355855bcd10 100644
--- a/library/std/src/sys/unix/ext/process.rs
+++ b/library/std/src/os/unix/process.rs
diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/os/unix/raw.rs
index c292955cb4e..c292955cb4e 100644
--- a/library/std/src/sys/unix/ext/raw.rs
+++ b/library/std/src/os/unix/raw.rs
diff --git a/library/std/src/sys/unix/ext/thread.rs b/library/std/src/os/unix/thread.rs
index 7221da1a9a7..7221da1a9a7 100644
--- a/library/std/src/sys/unix/ext/thread.rs
+++ b/library/std/src/os/unix/thread.rs
diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/os/unix/ucred.rs
index 1b4c18d3d84..1b4c18d3d84 100644
--- a/library/std/src/sys/unix/ext/ucred.rs
+++ b/library/std/src/os/unix/ucred.rs
diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs
index 42d79418cf7..42d79418cf7 100644
--- a/library/std/src/sys/unix/ext/ucred/tests.rs
+++ b/library/std/src/os/unix/ucred/tests.rs
diff --git a/library/std/src/os/wasi.rs b/library/std/src/os/wasi.rs
deleted file mode 100644
index d25b8d39ed6..00000000000
--- a/library/std/src/os/wasi.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! WASI-specific definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::ext::*;
diff --git a/library/std/src/sys/wasi/ext/ffi.rs b/library/std/src/os/wasi/ffi.rs
index f71f316d1ba..f71f316d1ba 100644
--- a/library/std/src/sys/wasi/ext/ffi.rs
+++ b/library/std/src/os/wasi/ffi.rs
diff --git a/library/std/src/sys/wasi/ext/fs.rs b/library/std/src/os/wasi/fs.rs
index ba4057bd34c..ba4057bd34c 100644
--- a/library/std/src/sys/wasi/ext/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/os/wasi/io.rs
index b2e79cc1b4a..b2e79cc1b4a 100644
--- a/library/std/src/sys/wasi/ext/io.rs
+++ b/library/std/src/os/wasi/io.rs
diff --git a/library/std/src/sys/wasi/ext/mod.rs b/library/std/src/os/wasi/mod.rs
index b08402f0776..66edb953677 100644
--- a/library/std/src/sys/wasi/ext/mod.rs
+++ b/library/std/src/os/wasi/mod.rs
@@ -25,6 +25,7 @@
 //! }
 //! ```
 
+#![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![doc(cfg(target_os = "wasi"))]
 
diff --git a/library/std/src/sys/windows/ext/ffi.rs b/library/std/src/os/windows/ffi.rs
index c89b9ff1efa..c89b9ff1efa 100644
--- a/library/std/src/sys/windows/ext/ffi.rs
+++ b/library/std/src/os/windows/ffi.rs
diff --git a/library/std/src/sys/windows/ext/fs.rs b/library/std/src/os/windows/fs.rs
index b20eafb4d53..b20eafb4d53 100644
--- a/library/std/src/sys/windows/ext/fs.rs
+++ b/library/std/src/os/windows/fs.rs
diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/os/windows/io.rs
index 31b5d015ed0..31b5d015ed0 100644
--- a/library/std/src/sys/windows/ext/io.rs
+++ b/library/std/src/os/windows/io.rs
diff --git a/library/std/src/sys/windows/ext/mod.rs b/library/std/src/os/windows/mod.rs
index 613d3dc189a..52ac508f9f7 100644
--- a/library/std/src/sys/windows/ext/mod.rs
+++ b/library/std/src/os/windows/mod.rs
@@ -8,7 +8,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![doc(cfg(windows))]
-#![allow(missing_docs)]
 
 pub mod ffi;
 pub mod fs;
diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/os/windows/process.rs
index 67756b15531..67756b15531 100644
--- a/library/std/src/sys/windows/ext/process.rs
+++ b/library/std/src/os/windows/process.rs
diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/os/windows/raw.rs
index 5014e008eb5..5014e008eb5 100644
--- a/library/std/src/sys/windows/ext/raw.rs
+++ b/library/std/src/os/windows/raw.rs
diff --git a/library/std/src/sys/windows/ext/thread.rs b/library/std/src/os/windows/thread.rs
index 6bd02054f71..6bd02054f71 100644
--- a/library/std/src/sys/windows/ext/thread.rs
+++ b/library/std/src/os/windows/thread.rs
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index cd6b0b2d7ee..96ab32104ea 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -445,7 +445,27 @@ mod prim_unit {}
 /// Note that here the call to [`drop`] is for clarity - it indicates
 /// that we are done with the given value and it should be destroyed.
 ///
-/// ## 3. Get it from C.
+/// ## 3. Create it using `ptr::addr_of!`
+///
+/// Instead of coercing a reference to a raw pointer, you can use the macros
+/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
+/// These macros allow you to create raw pointers to fields to which you cannot
+/// create a reference (without causing undefined behaviour), such as an
+/// unaligned field. This might be necessary if packed structs or uninitialized
+/// memory is involved.
+///
+/// ```
+/// #[derive(Debug, Default, Copy, Clone)]
+/// #[repr(C, packed)]
+/// struct S {
+///     aligned: u8,
+///     unaligned: u32,
+/// }
+/// let s = S::default();
+/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion
+/// ```
+///
+/// ## 4. Get it from C.
 ///
 /// ```
 /// # #![feature(rustc_private)]
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 0c49a6fb6de..15a76bbd2c9 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -24,7 +24,6 @@ pub mod args;
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fd;
 pub mod fs;
 #[path = "../unsupported/io.rs"]
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 2450a7aac5e..f813587b1b3 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -49,80 +49,27 @@ cfg_if::cfg_if! {
     }
 }
 
-// Import essential modules from both platforms when documenting. These are
-// then later used in the `std::os` module when documenting, for example,
-// Windows when we're compiling for Linux.
+// Import essential modules from platforms used in `std::os` when documenting.
+//
+// Note that on some platforms those modules don't compile
+// (missing things in `libc` which is empty), so they are not included in `std::os` and can be
+// omitted here as well.
 
 #[cfg(doc)]
+#[cfg(not(any(
+    all(target_arch = "wasm32", not(target_os = "wasi")),
+    all(target_vendor = "fortanix", target_env = "sgx")
+)))]
 cfg_if::cfg_if! {
-    if #[cfg(unix)] {
-        // On unix we'll document what's already available
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use self::ext as unix_ext;
-    } else if #[cfg(any(target_os = "hermit",
-                        all(target_arch = "wasm32", not(target_os = "wasi")),
-                        all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On non-WASI wasm right now the module below doesn't compile
-        // (missing things in `libc` which is empty) so just omit everything
-        // with an empty module
-        #[unstable(issue = "none", feature = "std_internals")]
-        #[allow(missing_docs)]
-        pub mod unix_ext {}
-    } else {
-        #[path = "unix/ext/mod.rs"]
-        pub mod unix_ext;
-    }
-}
-
-#[cfg(doc)]
-cfg_if::cfg_if! {
-    if #[cfg(windows)] {
-        // On windows we'll just be documenting what's already available
-        #[allow(missing_docs)]
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use self::ext as windows_ext;
-    } else if #[cfg(any(target_os = "hermit",
-                        all(target_arch = "wasm32", not(target_os = "wasi")),
-                        all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On non-WASI wasm right now the shim below doesn't compile, so
-        // just omit it
-        #[unstable(issue = "none", feature = "std_internals")]
-        #[allow(missing_docs)]
-        pub mod windows_ext {}
-    } else {
-        // On all other platforms (aka linux/osx/etc) then pull in a "minimal"
+    if #[cfg(not(windows))] {
+        // On non-Windows platforms (aka linux/osx/etc) pull in a "minimal"
         // amount of windows goop which ends up compiling
+
         #[macro_use]
         #[path = "windows/compat.rs"]
-        mod compat;
+        pub mod compat;
 
         #[path = "windows/c.rs"]
-        mod c;
-
-        #[path = "windows/ext/mod.rs"]
-        pub mod windows_ext;
-    }
-}
-
-#[cfg(doc)]
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "wasi")] {
-        // On WASI we'll document what's already available
-        #[stable(feature = "wasi_ext_doc", since = "1.35.0")]
-        pub use self::ext as wasi_ext;
-    } else if #[cfg(any(target_os = "hermit",
-                        target_arch = "wasm32",
-                        all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On non-WASI wasm right now the module below doesn't compile
-        // (missing things in `libc` which is empty) so just omit everything
-        // with an empty module
-        #[unstable(issue = "none", feature = "std_internals")]
-        #[allow(missing_docs)]
-        pub mod wasi_ext {}
-    } else {
-        // On other platforms like Windows document the bare bones of WASI
-        #[path = "wasi/ext/mod.rs"]
-        #[stable(feature = "wasi_ext_doc", since = "1.35.0")]
-        pub mod wasi_ext;
+        pub mod c;
     }
 }
diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs
index a5e45303476..f9536c4203d 100644
--- a/library/std/src/sys/sgx/abi/mod.rs
+++ b/library/std/src/sys/sgx/abi/mod.rs
@@ -62,10 +62,12 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
     // FIXME: how to support TLS in library mode?
     let tls = Box::new(tls::Tls::new());
-    let _tls_guard = unsafe { tls.activate() };
+    let tls_guard = unsafe { tls.activate() };
 
     if secondary {
-        super::thread::Thread::entry();
+        let join_notifier = super::thread::Thread::entry();
+        drop(tls_guard);
+        drop(join_notifier);
 
         EntryReturn(0, 0)
     } else {
diff --git a/library/std/src/sys/sgx/ext/mod.rs b/library/std/src/sys/sgx/ext/mod.rs
deleted file mode 100644
index 258ad3cd218..00000000000
--- a/library/std/src/sys/sgx/ext/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![unstable(feature = "sgx_platform", issue = "56975")]
-
-pub mod arch;
-pub mod ffi;
-pub mod io;
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index bf3bd57e982..cdfceca19fc 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -17,7 +17,6 @@ pub mod args;
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fd;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs
index 55ef460cc90..67e2e8b59d3 100644
--- a/library/std/src/sys/sgx/thread.rs
+++ b/library/std/src/sys/sgx/thread.rs
@@ -9,26 +9,37 @@ pub struct Thread(task_queue::JoinHandle);
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
 
+pub use self::task_queue::JoinNotifier;
+
 mod task_queue {
-    use crate::sync::mpsc;
+    use super::wait_notify;
     use crate::sync::{Mutex, MutexGuard, Once};
 
-    pub type JoinHandle = mpsc::Receiver<()>;
+    pub type JoinHandle = wait_notify::Waiter;
+
+    pub struct JoinNotifier(Option<wait_notify::Notifier>);
+
+    impl Drop for JoinNotifier {
+        fn drop(&mut self) {
+            self.0.take().unwrap().notify();
+        }
+    }
 
     pub(super) struct Task {
         p: Box<dyn FnOnce()>,
-        done: mpsc::Sender<()>,
+        done: JoinNotifier,
     }
 
     impl Task {
         pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) {
-            let (done, recv) = mpsc::channel();
+            let (done, recv) = wait_notify::new();
+            let done = JoinNotifier(Some(done));
             (Task { p, done }, recv)
         }
 
-        pub(super) fn run(self) {
+        pub(super) fn run(self) -> JoinNotifier {
             (self.p)();
-            let _ = self.done.send(());
+            self.done
         }
     }
 
@@ -47,6 +58,48 @@ mod task_queue {
     }
 }
 
+/// This module provides a synchronization primitive that does not use thread
+/// local variables. This is needed for signaling that a thread has finished
+/// execution. The signal is sent once all TLS destructors have finished at
+/// which point no new thread locals should be created.
+pub mod wait_notify {
+    use super::super::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
+    use crate::sync::Arc;
+
+    pub struct Notifier(Arc<SpinMutex<WaitVariable<bool>>>);
+
+    impl Notifier {
+        /// Notify the waiter. The waiter is either notified right away (if
+        /// currently blocked in `Waiter::wait()`) or later when it calls the
+        /// `Waiter::wait()` method.
+        pub fn notify(self) {
+            let mut guard = self.0.lock();
+            *guard.lock_var_mut() = true;
+            let _ = WaitQueue::notify_one(guard);
+        }
+    }
+
+    pub struct Waiter(Arc<SpinMutex<WaitVariable<bool>>>);
+
+    impl Waiter {
+        /// Wait for a notification. If `Notifier::notify()` has already been
+        /// called, this will return immediately, otherwise the current thread
+        /// is blocked until notified.
+        pub fn wait(self) {
+            let guard = self.0.lock();
+            if *guard.lock_var() {
+                return;
+            }
+            WaitQueue::wait(guard, || {});
+        }
+    }
+
+    pub fn new() -> (Notifier, Waiter) {
+        let inner = Arc::new(SpinMutex::new(WaitVariable::new(false)));
+        (Notifier(inner.clone()), Waiter(inner))
+    }
+}
+
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
@@ -57,7 +110,7 @@ impl Thread {
         Ok(Thread(handle))
     }
 
-    pub(super) fn entry() {
+    pub(super) fn entry() -> JoinNotifier {
         let mut pending_tasks = task_queue::lock();
         let task = rtunwrap!(Some, pending_tasks.pop());
         drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
@@ -78,7 +131,7 @@ impl Thread {
     }
 
     pub fn join(self) {
-        let _ = self.0.recv();
+        self.0.wait();
     }
 }
 
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 45bae25a0c3..79617aa77b7 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -116,7 +116,7 @@ cfg_has_statx! {{
 
         match STATX_STATE.load(Ordering::Relaxed) {
             0 => {
-                // It is a trick to call `statx` with NULL pointers to check if the syscall
+                // It is a trick to call `statx` with null pointers to check if the syscall
                 // is available. According to the manual, it is expected to fail with EFAULT.
                 // We do this mainly for performance, since it is nearly hundreds times
                 // faster than a normal successful call.
@@ -450,7 +450,7 @@ impl Iterator for ReadDir {
                 super::os::set_errno(0);
                 let entry_ptr = libc::readdir(self.inner.dirp.0);
                 if entry_ptr.is_null() {
-                    // NULL can mean either the end is reached or an error occurred.
+                    // null can mean either the end is reached or an error occurred.
                     // So we had to clear errno beforehand to check for an error now.
                     return match super::os::errno() {
                         0 => None,
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 6c4fbaf2734..57d91441b6f 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -15,7 +15,6 @@ pub mod args;
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fd;
 pub mod fs;
 pub mod futex;
@@ -149,6 +148,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ETIMEDOUT => ErrorKind::TimedOut,
         libc::EEXIST => ErrorKind::AlreadyExists,
         libc::ENOSYS => ErrorKind::Unsupported,
+        libc::ENOMEM => ErrorKind::OutOfMemory,
 
         // These two constants can have the same value on some systems,
         // but different values on others, so we can't use a match
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 984c08c2ad5..51c3e5d175c 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -155,12 +155,10 @@ pub fn getcwd() -> io::Result<PathBuf> {
 pub fn chdir(p: &path::Path) -> io::Result<()> {
     let p: &OsStr = p.as_ref();
     let p = CString::new(p.as_bytes())?;
-    unsafe {
-        match libc::chdir(p.as_ptr()) == (0 as c_int) {
-            true => Ok(()),
-            false => Err(io::Error::last_os_error()),
-        }
+    if unsafe { libc::chdir(p.as_ptr()) } != 0 {
+        return Err(io::Error::last_os_error());
     }
+    Ok(())
 }
 
 pub struct SplitPaths<'a> {
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index b9dcc4e4b9e..c5bdd1bda4a 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -153,7 +153,7 @@ impl Command {
     }
 
     pub fn arg(&mut self, arg: &OsStr) {
-        // Overwrite the trailing NULL pointer in `argv` and then add a new null
+        // Overwrite the trailing null pointer in `argv` and then add a new null
         // pointer.
         let arg = os2c(arg, &mut self.saw_nul);
         self.argv.0[self.args.len()] = arg.as_ptr();
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index 37f74fcc052..45a829c0cd2 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -33,7 +33,6 @@ pub mod mutex;
 pub mod net;
 pub mod os;
 pub use crate::sys_common::os_str_bytes as os_str;
-pub mod ext;
 #[path = "../unix/path.rs"]
 pub mod path;
 #[path = "../unsupported/pipe.rs"]
@@ -77,6 +76,7 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
         wasi::ERRNO_EXIST => AlreadyExists,
         wasi::ERRNO_AGAIN => WouldBlock,
         wasi::ERRNO_NOSYS => Unsupported,
+        wasi::ERRNO_NOMEM => OutOfMemory,
         _ => Other,
     }
 }
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 3e4176ef7f8..7ea6048e94a 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -168,6 +168,8 @@ pub const ERROR_FILE_NOT_FOUND: DWORD = 2;
 pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
 pub const ERROR_ACCESS_DENIED: DWORD = 5;
 pub const ERROR_INVALID_HANDLE: DWORD = 6;
+pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8;
+pub const ERROR_OUTOFMEMORY: DWORD = 14;
 pub const ERROR_NO_MORE_FILES: DWORD = 18;
 pub const ERROR_HANDLE_EOF: DWORD = 38;
 pub const ERROR_FILE_EXISTS: DWORD = 80;
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index ddb6ac5f55c..cc60ca375ea 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -18,7 +18,6 @@ pub mod c;
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fs;
 pub mod handle;
 pub mod io;
@@ -71,6 +70,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
         c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput,
+        c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return ErrorKind::OutOfMemory,
         c::ERROR_SEM_TIMEOUT
         | c::WAIT_TIMEOUT
         | c::ERROR_DRIVER_CANCEL_TIMEOUT
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index abd5b778483..1f5f26e3e14 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -722,7 +722,7 @@ pub mod os {
     unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
         // SAFETY:
         //
-        // The OS TLS ensures that this key contains a NULL value when this
+        // The OS TLS ensures that this key contains a null value when this
         // destructor starts to run. We set it back to a sentinel value of 1 to
         // ensure that any future calls to `get` for this thread will return
         // `None`.
diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs
index 80e6798d847..f33d6129619 100644
--- a/library/std/src/thread/local/tests.rs
+++ b/library/std/src/thread/local/tests.rs
@@ -1,4 +1,5 @@
 use crate::cell::{Cell, UnsafeCell};
+use crate::sync::atomic::{AtomicU8, Ordering};
 use crate::sync::mpsc::{channel, Sender};
 use crate::thread::{self, LocalKey};
 use crate::thread_local;
@@ -207,3 +208,110 @@ fn dtors_in_dtors_in_dtors_const_init() {
     });
     rx.recv().unwrap();
 }
+
+// This test tests that TLS destructors have run before the thread joins. The
+// test has no false positives (meaning: if the test fails, there's actually
+// an ordering problem). It may have false negatives, where the test passes but
+// join is not guaranteed to be after the TLS destructors. However, false
+// negatives should be exceedingly rare due to judicious use of
+// thread::yield_now and running the test several times.
+#[test]
+fn join_orders_after_tls_destructors() {
+    // We emulate a synchronous MPSC rendezvous channel using only atomics and
+    // thread::yield_now. We can't use std::mpsc as the implementation itself
+    // may rely on thread locals.
+    //
+    // The basic state machine for an SPSC rendezvous channel is:
+    //           FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS
+    // where the first transition is done by the “receiving” thread and the 2nd
+    // transition is done by the “sending” thread.
+    //
+    // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and
+    // `THREAD1_WAITING` to block until all threads are actually running.
+    //
+    // A thread that joins on the “receiving” thread completion should never
+    // observe the channel in the `THREAD1_WAITING` state. If this does occur,
+    // we switch to the “poison” state `THREAD2_JOINED` and panic all around.
+    // (This is equivalent to “sending” from an alternate producer thread.)
+    const FRESH: u8 = 0;
+    const THREAD2_LAUNCHED: u8 = 1;
+    const THREAD1_WAITING: u8 = 2;
+    const MAIN_THREAD_RENDEZVOUS: u8 = 3;
+    const THREAD2_JOINED: u8 = 4;
+    static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH);
+
+    for _ in 0..10 {
+        SYNC_STATE.store(FRESH, Ordering::SeqCst);
+
+        let jh = thread::Builder::new()
+            .name("thread1".into())
+            .spawn(move || {
+                struct TlDrop;
+
+                impl Drop for TlDrop {
+                    fn drop(&mut self) {
+                        let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst);
+                        loop {
+                            match sync_state {
+                                THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(),
+                                MAIN_THREAD_RENDEZVOUS => break,
+                                THREAD2_JOINED => panic!(
+                                    "Thread 1 still running after thread 2 joined on thread 1"
+                                ),
+                                v => unreachable!("sync state: {}", v),
+                            }
+                            sync_state = SYNC_STATE.load(Ordering::SeqCst);
+                        }
+                    }
+                }
+
+                thread_local! {
+                    static TL_DROP: TlDrop = TlDrop;
+                }
+
+                TL_DROP.with(|_| {});
+
+                loop {
+                    match SYNC_STATE.load(Ordering::SeqCst) {
+                        FRESH => thread::yield_now(),
+                        THREAD2_LAUNCHED => break,
+                        v => unreachable!("sync state: {}", v),
+                    }
+                }
+            })
+            .unwrap();
+
+        let jh2 = thread::Builder::new()
+            .name("thread2".into())
+            .spawn(move || {
+                assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH);
+                jh.join().unwrap();
+                match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) {
+                    MAIN_THREAD_RENDEZVOUS => return,
+                    THREAD2_LAUNCHED | THREAD1_WAITING => {
+                        panic!("Thread 2 running after thread 1 join before main thread rendezvous")
+                    }
+                    v => unreachable!("sync state: {:?}", v),
+                }
+            })
+            .unwrap();
+
+        loop {
+            match SYNC_STATE.compare_exchange_weak(
+                THREAD1_WAITING,
+                MAIN_THREAD_RENDEZVOUS,
+                Ordering::SeqCst,
+                Ordering::SeqCst,
+            ) {
+                Ok(_) => break,
+                Err(FRESH) => thread::yield_now(),
+                Err(THREAD2_LAUNCHED) => thread::yield_now(),
+                Err(THREAD2_JOINED) => {
+                    panic!("Main thread rendezvous after thread 2 joined thread 1")
+                }
+                v => unreachable!("sync state: {:?}", v),
+            }
+        }
+        jh2.join().unwrap();
+    }
+}
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/tests.rs b/src/bootstrap/builder/tests.rs
index a881512e988..4d7c207e3ab 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -489,6 +489,7 @@ mod dist {
             compare_mode: None,
             rustfix_coverage: false,
             pass: None,
+            run: None,
         };
 
         let build = Build::new(config);
@@ -529,6 +530,7 @@ mod dist {
             compare_mode: None,
             rustfix_coverage: false,
             pass: None,
+            run: None,
         };
 
         let build = Build::new(config);
@@ -584,6 +586,7 @@ mod dist {
             compare_mode: None,
             rustfix_coverage: false,
             pass: None,
+            run: None,
         };
         // Make sure rustfmt binary not being found isn't an error.
         config.channel = "beta".to_string();
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 9b76c8b9a2d..8561a2a39b8 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:literal, $($alias:literal, )* $source_type:path) => {
+    ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub target: TargetSelection,
@@ -289,7 +289,7 @@ macro_rules! tool_check_step {
         impl Step for $name {
             type Output = ();
             const ONLY_HOSTS: bool = true;
-            const DEFAULT: bool = true;
+            const DEFAULT: bool = true $( && $default )?;
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                 run.paths(&[ $path, $($alias),* ])
@@ -368,7 +368,7 @@ tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InT
 // rejected.
 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
 
-tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree);
+tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 6044899c237..d961e067db3 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -103,6 +103,7 @@ pub enum Subcommand {
         bless: bool,
         compare_mode: Option<String>,
         pass: Option<String>,
+        run: Option<String>,
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
@@ -222,8 +223,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
              VALUE overrides the skip-rebuild option in config.toml.",
             "VALUE",
         );
-        opts.optopt("", "rust-profile-generate", "rustc error format", "FORMAT");
-        opts.optopt("", "rust-profile-use", "rustc error format", "FORMAT");
+        opts.optopt("", "rust-profile-generate", "generate PGO profile with rustc build", "FORMAT");
+        opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "FORMAT");
 
         // We can't use getopt to parse the options until we have completed specifying which
         // options are valid, but under the current implementation, some options are conditional on
@@ -293,6 +294,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
                     "force {check,build,run}-pass tests to this mode.",
                     "check | build | run",
                 );
+                opts.optopt("", "run", "whether to execute run-* tests", "auto | always | never");
                 opts.optflag(
                     "",
                     "rustfix-coverage",
@@ -556,6 +558,7 @@ Arguments:
                 bless: matches.opt_present("bless"),
                 compare_mode: matches.opt_str("compare-mode"),
                 pass: matches.opt_str("pass"),
+                run: matches.opt_str("run"),
                 test_args: matches.opt_strs("test-args"),
                 rustc_args: matches.opt_strs("rustc-args"),
                 fail_fast: !matches.opt_present("no-fail-fast"),
@@ -742,6 +745,13 @@ impl Subcommand {
         }
     }
 
+    pub fn run(&self) -> Option<&str> {
+        match *self {
+            Subcommand::Test { ref run, .. } => run.as_ref().map(|s| &s[..]),
+            _ => None,
+        }
+    }
+
     pub fn open(&self) -> bool {
         match *self {
             Subcommand::Doc { open, .. } => open,
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 965d1162145..c98398cf1d2 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -183,6 +183,7 @@ impl Step for Cargotest {
             builder,
             cmd.arg(&cargo)
                 .arg(&out_dir)
+                .args(builder.config.cmd.test_args())
                 .env("RUSTC", builder.rustc(compiler))
                 .env("RUSTDOC", builder.rustdoc(compiler)),
         );
@@ -830,6 +831,7 @@ impl Step for RustdocGUI {
             command.arg("src/test/rustdoc-gui/lib.rs").arg("-o").arg(&out_dir);
             builder.run(&mut command);
 
+            let mut tests = Vec::new();
             for file in fs::read_dir("src/test/rustdoc-gui").unwrap() {
                 let file = file.unwrap();
                 let file_path = file.path();
@@ -838,13 +840,17 @@ impl Step for RustdocGUI {
                 if !file_name.to_str().unwrap().ends_with(".goml") {
                     continue;
                 }
+                tests.push(file_path);
+            }
+            tests.sort_unstable();
+            for test in tests {
                 let mut command = Command::new(&nodejs);
                 command
                     .arg("src/tools/rustdoc-gui/tester.js")
                     .arg("--doc-folder")
                     .arg(out_dir.join("test_docs"))
                     .arg("--test-file")
-                    .arg(file_path);
+                    .arg(test);
                 builder.run(&mut command);
             }
         } else {
@@ -1110,6 +1116,19 @@ struct Compiletest {
     compare_mode: Option<&'static str>,
 }
 
+impl Compiletest {
+    fn add_lld_flags(builder: &Builder<'_>, target: TargetSelection, flags: &mut Vec<String>) {
+        if builder.config.use_lld {
+            if builder.is_fuse_ld_lld(target) {
+                flags.push("-Clink-arg=-fuse-ld=lld".to_string());
+            }
+
+            let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
+            flags.push(format!("-Clink-arg=-Wl,{}", threads));
+        }
+    }
+}
+
 impl Step for Compiletest {
     type Output = ();
 
@@ -1227,6 +1246,11 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             cmd.arg(pass);
         }
 
+        if let Some(ref run) = builder.config.cmd.run() {
+            cmd.arg("--run");
+            cmd.arg(run);
+        }
+
         if let Some(ref nodejs) = builder.config.nodejs {
             cmd.arg("--nodejs").arg(nodejs);
         }
@@ -1250,18 +1274,12 @@ note: if you're sure you want to do this, please open an issue as to why. In the
 
         let mut hostflags = flags.clone();
         hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
-        if builder.is_fuse_ld_lld(compiler.host) {
-            hostflags.push("-Clink-args=-fuse-ld=lld".to_string());
-            hostflags.push("-Clink-arg=-Wl,--threads=1".to_string());
-        }
+        Self::add_lld_flags(builder, compiler.host, &mut hostflags);
         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
 
         let mut targetflags = flags;
         targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
-        if builder.is_fuse_ld_lld(target) {
-            targetflags.push("-Clink-args=-fuse-ld=lld".to_string());
-            targetflags.push("-Clink-arg=-Wl,--threads=1".to_string());
-        }
+        Self::add_lld_flags(builder, target, &mut targetflags);
         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
 
         cmd.arg("--docck-python").arg(builder.python());
@@ -1709,6 +1727,9 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
     builder.info(&format!("doc tests for: {}", markdown.display()));
     let mut cmd = builder.rustdoc_cmd(compiler);
     builder.add_rust_test_threads(&mut cmd);
+    // allow for unstable options such as new editions
+    cmd.arg("-Z");
+    cmd.arg("unstable-options");
     cmd.arg("--test");
     cmd.arg(markdown);
     cmd.env("RUSTC_BOOTSTRAP", "1");
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/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index 8070e90f155..7b540b5c6e9 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -9,7 +9,7 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 # Update both macOS's and Windows's tarballs when bumping the version here.
-LLVM_VERSION="10.0.0"
+LLVM_VERSION="12.0.0"
 
 if isMacOS; then
     # If the job selects a specific Xcode version, use that instead of
@@ -18,7 +18,8 @@ if isMacOS; then
         bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin"
     else
         file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
-        curl -f "${file}" | tar xJf -
+        retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
+        tar xJf "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
         bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin"
     fi
 
@@ -42,23 +43,15 @@ elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then
     # clang has an output mode compatible with MinGW that we need. If it does we
     # should switch to clang for MinGW as well!
     #
-    # Note that the LLVM installer is an NSIS installer
-    #
-    # Original downloaded here came from:
-    #
-    #   https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe
-    #
-    # That installer was run through `wine ./installer.exe /S /NCRC` on Linux
-    # and then the resulting installation directory (found in
-    # `$HOME/.wine/drive_c/Program Files/LLVM`) was packaged up into a tarball.
-    # We've had issues otherwise that the installer will randomly hang, provide
-    # not a lot of useful information, pollute global state, etc. In general the
-    # tarball is just more confined and easier to deal with when working with
-    # various CI environments.
+    # The LLVM installer is an NSIS installer, which we can extract with 7z. We
+    # don't want to run the installer directly; extracting it is more reliable
+    # in CI environments.
 
-    mkdir -p citools
+    mkdir -p citools/clang-rust
     cd citools
-    curl -f "${MIRRORS_BASE}/LLVM-${LLVM_VERSION}-win64.tar.gz" | tar xzf -
+    retry curl -f "${MIRRORS_BASE}/LLVM-${LLVM_VERSION}-win64.exe" \
+        -o "LLVM-${LLVM_VERSION}-win64.exe"
+    7z x -oclang-rust/ "LLVM-${LLVM_VERSION}-win64.exe"
     ciCommandSetEnv RUST_CONFIGURE_ARGS \
         "${RUST_CONFIGURE_ARGS} --set llvm.clang-cl=$(pwd)/clang-rust/bin/clang-cl.exe"
 fi
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index b3c67b84da6..f9a7599c497 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -113,7 +113,7 @@ The `std` column in the table below has the following meanings:
 [`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
@@ -194,7 +194,7 @@ The `host` column indicates whether the codebase includes support for building
 host tools.
 
 target | std | host | notes
--------|-----|------|-------
+-------|:---:|:----:|-------
 `aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
 `aarch64-apple-ios-sim` | ? |  | Apple iOS Simulator on ARM64
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md
index a2cb0351916..cc02b294b44 100644
--- a/src/doc/rustc/src/target-tier-policy.md
+++ b/src/doc/rustc/src/target-tier-policy.md
@@ -102,7 +102,7 @@ place minimal requirements on the introduction of targets.
 
 A proposed new tier 3 target must be reviewed and approved by a member of the
 compiler team based on these requirements. The reviewer may choose to gauge
-broader compiler team consensus via a Major Change Proposal (MCP).
+broader compiler team consensus via a [Major Change Proposal (MCP)][MCP].
 
 A proposed target or target-specific patch that substantially changes code
 shared with other targets (not just target-specific code) must be reviewed and
@@ -223,8 +223,8 @@ patches that fail to build on a target. Thus, we place requirements that ensure
 the target will not block forward progress of the Rust project.
 
 A proposed new tier 2 target must be reviewed and approved by the compiler team
-based on these requirements. Such review and approval may occur via a Major
-Change Proposal (MCP).
+based on these requirements. Such review and approval may occur via a [Major
+Change Proposal (MCP)][MCP].
 
 In addition, the infrastructure team must approve the integration of the target
 into Continuous Integration (CI), and the tier 2 CI-related requirements. This
@@ -391,7 +391,7 @@ development platform, not just a compilation target.
 
 A proposed new tier 2 target with host tools must be reviewed and approved by
 the compiler team based on these requirements. Such review and approval may
-occur via a Major Change Proposal (MCP).
+occur via a [Major Change Proposal (MCP)][MCP].
 
 In addition, the infrastructure team must approve the integration of the
 target's host tools into Continuous Integration (CI), and the CI-related
@@ -648,3 +648,5 @@ for demotion of a tier 1 target (with or without host tools) requires a full
 RFC process, with approval by the compiler and release teams. Any such proposal
 will be communicated widely to the Rust community, both when initially proposed
 and before being dropped from a stable release.
+
+[MCP]: https://forge.rust-lang.org/compiler/mcp.html
diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
new file mode 100644
index 00000000000..f7c2a26f018
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
@@ -0,0 +1,346 @@
+# `instrument-coverage`
+
+The tracking issue for this feature is: [#79121].
+
+[#79121]: https://github.com/rust-lang/rust/issues/79121
+
+---
+
+## Introduction
+
+The Rust compiler includes two code coverage implementations:
+
+-   A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo.
+-   A source-based code coverage implementation, enabled with `-Z instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data.
+
+This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-Z instrument-coverage` compiler flag.
+
+## How it works
+
+When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
+
+-   Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
+-   Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted.
+
+When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
+
+[`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic
+[llvm code coverage mapping format]: https://llvm.org/docs/CoverageMappingFormat.html
+
+> **Note**: `-Z instrument-coverage` also automatically enables `-Z symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended, but be aware that this demangler is also experimental. The `v0` demangler can be overridden by explicitly adding `-Z symbol-mangling-version=legacy`.
+
+[#60705]: https://github.com/rust-lang/rust/issues/60705
+
+## Enable coverage profiling in the Rust compiler
+
+Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-Z instrument-coverage` generates an error that the profiler runtime is missing.
+
+The Rust `nightly` distribution channel includes the profiler runtime, by default.
+
+> **Important**: If you are building the Rust compiler from the source distribution, the profiler runtime is _not_ enabled in the default `config.toml.example`. Edit your `config.toml` file and ensure the `profiler` feature is set it to `true` (either under the `[build]` section, or under the settings for an individual `[target.<triple>]`):
+>
+> ```toml
+> # Build the profiler runtime (required when compiling with options that depend
+> # on this runtime, such as `-C profile-generate` or `-Z  instrument-coverage`).
+> profiler = true
+> ```
+
+### Building the demangler
+
+LLVM coverage reporting tools generate results that can include function names and other symbol references, and the raw coverage results report symbols using the compiler's "mangled" version of the symbol names, which can be difficult to interpret. To work around this issue, LLVM coverage tools also support a user-specified symbol name demangler.
+
+One option for a Rust demangler is [`rustfilt`], which can be installed with:
+
+```shell
+cargo install rustfilt
+```
+
+Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with:
+
+```shell
+$ ./x.py build rust-demangler
+```
+
+[`rustfilt`]: https://crates.io/crates/rustfilt
+
+## Compiling with coverage enabled
+
+Set the `-Z instrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling.
+
+The default option generates coverage for all functions, including unused (never called) functions and generics. The compiler flag supports an optional value to tailor this behavior. (See [`-Z instrument-coverage=<options>`](#-z-instrument-coverageoptions), below.)
+
+With `cargo`, you can instrument your program binary _and_ dependencies at the same time.
+
+For example (if your project's Cargo.toml builds a binary by default):
+
+```shell
+$ cd your-project
+$ cargo clean
+$ RUSTFLAGS="-Z instrument-coverage" cargo build
+```
+
+If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate):
+
+```shell
+$ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \
+    RUSTFLAGS="-Z instrument-coverage" \
+    cargo build --example formatjson5
+```
+
+> **Note**: that some compiler options, combined with `-Z instrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect.
+
+## Running the instrumented binary to generate raw coverage profiling data
+
+In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`:
+
+```shell
+$ echo "{some: 'thing'}" | target/debug/examples/formatjson5 -
+```
+
+```json5
+{
+    some: "thing",
+}
+```
+
+After running this program, a new file, `default.profraw`, should be in the current working directory. It's often preferable to set a specific file name or path. You can change the output file using the environment variable `LLVM_PROFILE_FILE`:
+
+```shell
+$ echo "{some: 'thing'}" \
+    | LLVM_PROFILE_FILE="formatjson5.profraw" target/debug/examples/formatjson5 -
+...
+$ ls formatjson5.profraw
+formatjson5.profraw
+```
+
+If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing directory structure will be created. Additionally, the following special pattern strings are rewritten:
+
+-   `%p` - The process ID.
+-   `%h` - The hostname of the machine running the program.
+-   `%t` - The value of the TMPDIR environment variable.
+-   `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`).
+-   `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered.
+
+## Installing LLVM coverage tools
+
+LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
+
+-   The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
+-   If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
+-   You can install compatible versions of these tools via `rustup`.
+
+The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands!
+
+```shell
+$ rustup component add llvm-tools-preview
+$ cargo install cargo-binutils
+$ cargo profdata -- --help  # note the additional "--" preceding the tool-specific arguments
+```
+
+[`cargo-binutils`]: https://crates.io/crates/cargo-binutils
+
+## Creating coverage reports
+
+Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (or `cargo profdata -- merge`), which can combine multiple raw profiles and index them at the same time:
+
+```shell
+$ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata
+```
+
+Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`] (or `cargo cov -- report`), for a coverage summaries; and [`llvm-cov show`] (or `cargo cov -- show`), to see detailed coverage of lines and regions (character ranges) overlaid on the original source code.
+
+These commands have several display and filtering options. For example:
+
+```shell
+$ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \
+    -instr-profile=formatjson5.profdata \
+    -show-line-counts-or-regions \
+    -show-instantiations \
+    -name=add_quoted_string
+```
+
+<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="img/llvm-cov-show-01.png" class="center"/>
+<br/>
+<br/>
+
+Some of the more notable options in this example include:
+
+-   `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool)
+-   `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map)
+-   `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary)
+-   `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`)
+
+[`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge
+[`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report
+[`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show
+
+> **Note**: Coverage can also be disabled on an individual function by annotating the function with the [`no_coverage` attribute] (which requires the feature flag `#![feature(no_coverage)]`).
+
+[`no_coverage` attribute]: ../language-features/no-coverage.md
+
+## Interpreting reports
+
+There are four statistics tracked in a coverage summary:
+
+-   Function coverage is the percentage of functions that have been executed at least once. A function is considered to be executed if any of its instantiations are executed.
+-   Instantiation coverage is the percentage of function instantiations that have been executed at least once. Generic functions and functions generated from macros are two kinds of functions that may have multiple instantiations.
+-   Line coverage is the percentage of code lines that have been executed at least once. Only executable lines within function bodies are considered to be code lines.
+-   Region coverage is the percentage of code regions that have been executed at least once. A code region may span multiple lines: for example, in a large function body with no control flow. In other cases, a single line can contain multiple code regions: `return x || (y && z)` has countable code regions for `x` (which may resolve the expression, if `x` is `true`), `|| (y && z)` (executed only if `x` was `false`), and `return` (executed in either situation).
+
+Of these four statistics, function coverage is usually the least granular while region coverage is the most granular. The project-wide totals for each statistic are listed in the summary.
+
+## Test coverage
+
+A typical use case for coverage analysis is test coverage. Rust's source-based coverage tools can both measure your tests' code coverage as percentage, and pinpoint functions and branches not tested.
+
+The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate.
+
+Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-Z instrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.)
+
+```shell
+$ RUSTFLAGS="-Z instrument-coverage" \
+    LLVM_PROFILE_FILE="json5format-%m.profraw" \
+    cargo test --tests
+```
+
+Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
+
+```text
+   ...
+   Compiling json5format v0.1.3 ($HOME/json5format)
+    Finished test [unoptimized + debuginfo] target(s) in 14.60s
+
+     Running target/debug/deps/json5format-fececd4653271682
+running 25 tests
+...
+test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+
+     Running target/debug/deps/lib-30768f9c53506dc5
+running 31 tests
+...
+test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+```
+
+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 \
+    -sparse json5format-*.profraw -o json5format.profdata
+```
+
+Then run the `cov` tool, with the `profdata` file and all test binaries:
+
+```shell
+$ cargo cov -- report \
+    --use-color --ignore-filename-regex='/.cargo/registry' \
+    --instr-profile=json5format.profdata \
+    --object target/debug/deps/lib-30768f9c53506dc5 \
+    --object target/debug/deps/json5format-fececd4653271682
+$ cargo cov -- show \
+    --use-color --ignore-filename-regex='/.cargo/registry' \
+    --instr-profile=json5format.profdata \
+    --object target/debug/deps/lib-30768f9c53506dc5 \
+    --object target/debug/deps/json5format-fececd4653271682 \
+    --show-instantiations --show-line-counts-or-regions \
+    --Xdemangler=rustfilt | less -R
+```
+
+> **Note**: The command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results.\_
+
+### Tips for listing the binaries automatically
+
+For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like:
+
+```bash
+$ cargo cov -- report \
+    $( \
+      for file in \
+        $( \
+          RUSTFLAGS="-Z instrument-coverage" \
+            cargo test --tests --no-run --message-format=json \
+              | jq -r "select(.profile.test == true) | .filenames[]" \
+              | grep -v dSYM - \
+        ); \
+      do \
+        printf "%s %s " -object $file; \
+      done \
+    ) \
+  --instr-profile=json5format.profdata --summary-only # and/or other options
+```
+
+Adding `--no-run --message-format=json` to the _same_ `cargo test` command used to run
+the tests (including the same environment variables and flags) generates output in a JSON
+format that `jq` can easily query.
+
+The `printf` command takes this list and generates the `--object <binary>` arguments
+for each listed test binary.
+
+### Including doc tests
+
+The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417]
+
+To include doc tests in the coverage results, drop the `--tests` flag, and apply the
+`-Z instrument-coverage` flag, and some doc-test-specific options in the
+`RUSTDOCFLAGS` environment variable. (The `cargo profdata` command does not change.)
+
+```bash
+$ RUSTFLAGS="-Z instrument-coverage" \
+  RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
+  LLVM_PROFILE_FILE="json5format-%m.profraw" \
+    cargo test
+$ cargo profdata -- merge \
+    -sparse json5format-*.profraw -o json5format.profdata
+```
+
+The `-Z unstable-options --persist-doctests` flag is required, to save the test binaries
+(with their coverage maps) for `llvm-cov`.
+
+```bash
+$ cargo cov -- report \
+    $( \
+      for file in \
+        $( \
+          RUSTFLAGS="-Z instrument-coverage" \
+          RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
+            cargo test --no-run --message-format=json \
+              | jq -r "select(.profile.test == true) | .filenames[]" \
+              | grep -v dSYM - \
+        ) \
+        target/debug/doctestbins/*/rust_out; \
+      do \
+        [[ -x $file ]] && printf "%s %s " -object $file; \
+      done \
+    ) \
+  --instr-profile=json5format.profdata --summary-only # and/or other options
+```
+
+> **Note**: The differences in this `cargo cov` command, compared with the version without
+> doc tests, include:
+
+-   The `cargo test ... --no-run` command is updated with the same environment variables
+    and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE`
+    is only used when _running_ the tests.)
+-   The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out`
+    binaries generated for doc tests (note, however, that some `rust_out` files may not
+    be executable binaries).
+-   `[[ -x $file ]] &&` filters the files passed on to the `printf`, to include only
+    executable binaries.
+
+[^79417]:
+    There is ongoing work to resolve a known issue
+    [(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage
+    generates incorrect source line numbers in `llvm-cov show` results.
+
+## `-Z instrument-coverage=<options>`
+
+-   `-Z instrument-coverage=all`: Instrument all functions, including unused functions and unused generics. (This is the same as `-Z instrument-coverage`, with no value.)
+-   `-Z instrument-coverage=except-unused-generics`: Instrument all functions except unused generics.
+-   `-Z instrument-coverage=except-unused-functions`: Instrument only used (called) functions and instantiated generic functions.
+-   `-Z instrument-coverage=off`: Do not instrument any functions. (This is the same as simply not including the `-Z instrument-coverage` option.)
+
+## Other references
+
+Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.)
+
+[source-based code coverage in clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+[`json5format`]: https://crates.io/crates/json5format
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 f0ecb6871b1..cb65978e0a0 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
@@ -1,327 +1,5 @@
 # `source-based-code-coverage`
 
-The tracking issue for this feature is: [#79121].
+See compiler flag [`-Z instrument-coverage`].
 
-------------------------
-
-## Introduction
-
-The Rust compiler includes two code coverage implementations:
-
-* A GCC-compatible, gcov-based coverage implementation, enabled with [`-Zprofile`], which operates on DebugInfo.
-* A source-based code coverage implementation, enabled with `-Zinstrument-coverage`, which uses LLVM's native coverage instrumentation to generate very precise coverage data.
-
-This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-Zinstrument-coverage` compiler flag.
-
-## How it works
-
-When `-Zinstrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
-
-* Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
-* Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted.
-
-When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
-
-## Enable coverage profiling in the Rust compiler
-
-Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-Zinstrument-coverage` generates an error that the profiler runtime is missing.
-
-The Rust `nightly` distribution channel should include the profiler runtime, by default.
-
-*IMPORTANT:* If you are building the Rust compiler from the source distribution, the profiler runtime is *not* enabled in the default `config.toml.example`. Edit your `config.toml` file and ensure the `profiler` feature is set it to `true`:
-
-```toml
-# Build the profiler runtime (required when compiling with options that depend
-# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
-profiler = true
-```
-
-If changed, rebuild the Rust compiler (see [rustc-dev-guide-how-to-build-and-run]).
-
-### Building the demangler
-
-LLVM coverage reporting tools generate results that can include function names and other symbol references, and the raw coverage results report symbols using the compiler's "mangled" version of the symbol names, which can be difficult to interpret. To work around this issue, LLVM coverage tools also support a user-specified symbol name demangler.
-
-One option for a Rust demangler is [`rustfilt`], which can be installed with:
-
-```shell
-cargo install rustfilt
-```
-
-Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with:
-
-```shell
-$ ./x.py build rust-demangler
-```
-
-## Compiling with coverage enabled
-
-Set the `-Zinstrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling.
-
-With `cargo`, you can instrument your program binary *and* dependencies at the same time.
-
-For example (if your project's Cargo.toml builds a binary by default):
-
-```shell
-$ cd your-project
-$ cargo clean
-$ RUSTFLAGS="-Zinstrument-coverage" cargo build
-```
-
-If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate):
-
-```shell
-$ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \
-    RUSTFLAGS="-Zinstrument-coverage" \
-    cargo build --example formatjson5
-```
-
-Note that some compiler options, combined with `-Zinstrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect.
-
-## Running the instrumented binary to generate raw coverage profiling data
-
-In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`:
-
-```shell
-$ echo "{some: 'thing'}" | target/debug/examples/formatjson5 -
-```
-```json5
-{
-    some: 'thing',
-}
-```
-
-After running this program, a new file, `default.profraw`, should be in the current working directory. It's often preferable to set a specific file name or path. You can change the output file using the environment variable `LLVM_PROFILE_FILE`:
-
-
-```shell
-$ echo "{some: 'thing'}" \
-    | LLVM_PROFILE_FILE="formatjson5.profraw" target/debug/examples/formatjson5 -
-...
-$ ls formatjson5.profraw
-formatjson5.profraw
-```
-
-If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing directory structure will be created. Additionally, the following special pattern strings are rewritten:
-
-* `%p` - The process ID.
-* `%h` - The hostname of the machine running the program.
-* `%t` - The value of the TMPDIR environment variable.
-* `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`).
-* `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered.
-
-## Installing LLVM coverage tools
-
-LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
-
-* The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
-* If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
-* You can install compatible versions of these tools via `rustup`.
-
-The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands!
-
-```shell
-$ rustup component add llvm-tools-preview
-$ cargo install cargo-binutils
-$ cargo profdata -- --help  # note the additional "--" preceding the tool-specific arguments
-```
-
-## Creating coverage reports
-
-Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (or `cargo profdata -- merge`), which can combine multiple raw profiles and index them at the same time:
-
-```shell
-$ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata
-```
-
-Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`] (or `cargo cov -- report`), for a coverage summaries; and [`llvm-cov show`] (or `cargo cov -- show`), to see detailed coverage of lines and regions (character ranges) overlaid on the original source code.
-
-These commands have several display and filtering options. For example:
-
-```shell
-$ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \
-    -instr-profile=formatjson5.profdata \
-    -show-line-counts-or-regions \
-    -show-instantiations \
-    -name=add_quoted_string
-```
-
-<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="img/llvm-cov-show-01.png" class="center"/>
-<br/>
-<br/>
-
-Some of the more notable options in this example include:
-
-* `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool)
-* `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map)
-* `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary)
-* `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`)
-
-## Interpreting reports
-
-There are four statistics tracked in a coverage summary:
-
-* Function coverage is the percentage of functions that have been executed at least once. A function is considered to be executed if any of its instantiations are executed.
-* Instantiation coverage is the percentage of function instantiations that have been executed at least once. Generic functions and functions generated from macros are two kinds of functions that may have multiple instantiations.
-* Line coverage is the percentage of code lines that have been executed at least once. Only executable lines within function bodies are considered to be code lines.
-* Region coverage is the percentage of code regions that have been executed at least once. A code region may span multiple lines: for example, in a large function body with no control flow. In other cases, a single line can contain multiple code regions: `return x || (y && z)` has countable code regions for `x` (which may resolve the expression, if `x` is `true`), `|| (y && z)` (executed only if `x` was `false`), and `return` (executed in either situation).
-
-Of these four statistics, function coverage is usually the least granular while region coverage is the most granular. The project-wide totals for each statistic are listed in the summary.
-
-## Test coverage
-
-A typical use case for coverage analysis is test coverage. Rust's source-based coverage tools can both measure your tests' code coverage as percentage, and pinpoint functions and branches not tested.
-
-The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate.
-
-Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-Zinstrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.)
-
-```shell
-$ RUSTFLAGS="-Zinstrument-coverage" \
-    LLVM_PROFILE_FILE="json5format-%m.profraw" \
-    cargo test --tests
-```
-
-Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
-
-```text
-   ...
-   Compiling json5format v0.1.3 ($HOME/json5format)
-    Finished test [unoptimized + debuginfo] target(s) in 14.60s
-
-     Running target/debug/deps/json5format-fececd4653271682
-running 25 tests
-...
-test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
-
-     Running target/debug/deps/lib-30768f9c53506dc5
-running 31 tests
-...
-test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
-```
-
-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 \
-    -sparse json5format-*.profraw -o json5format.profdata
-```
-
-Then run the `cov` tool, with the `profdata` file and all test binaries:
-
-```shell
-$ cargo cov -- report \
-    --use-color --ignore-filename-regex='/.cargo/registry' \
-    --instr-profile=json5format.profdata \
-    --object target/debug/deps/lib-30768f9c53506dc5 \
-    --object target/debug/deps/json5format-fececd4653271682
-$ cargo cov -- show \
-    --use-color --ignore-filename-regex='/.cargo/registry' \
-    --instr-profile=json5format.profdata \
-    --object target/debug/deps/lib-30768f9c53506dc5 \
-    --object target/debug/deps/json5format-fececd4653271682 \
-    --show-instantiations --show-line-counts-or-regions \
-    --Xdemangler=rustfilt | less -R
-```
-
-_Note the command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results._
-
-### Tips for listing the binaries automatically
-
-For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like:
-
-```bash
-$ cargo cov -- report \
-    $( \
-      for file in \
-        $( \
-          RUSTFLAGS="-Zinstrument-coverage" \
-            cargo test --tests --no-run --message-format=json \
-              | jq -r "select(.profile.test == true) | .filenames[]" \
-              | grep -v dSYM - \
-        ); \
-      do \
-        printf "%s %s " -object $file; \
-      done \
-    ) \
-  --instr-profile=json5format.profdata --summary-only # and/or other options
-```
-
-Adding `--no-run --message-format=json` to the _same_ `cargo test` command used to run
-the tests (including the same environment variables and flags) generates output in a JSON
-format that `jq` can easily query.
-
-The `printf` command takes this list and generates the `--object <binary>` arguments
-for each listed test binary.
-
-### Including doc tests
-
-The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417]
-
-To include doc tests in the coverage results, drop the `--tests` flag, and apply the
-`-Zinstrument-coverage` flag, and some doc-test-specific options in the
-`RUSTDOCFLAGS` environment variable. (The `cargo profdata` command does not change.)
-
-```bash
-$ RUSTFLAGS="-Zinstrument-coverage" \
-  RUSTDOCFLAGS="-Zinstrument-coverage -Zunstable-options --persist-doctests target/debug/doctestbins" \
-  LLVM_PROFILE_FILE="json5format-%m.profraw" \
-    cargo test
-$ cargo profdata -- merge \
-    -sparse json5format-*.profraw -o json5format.profdata
-```
-
-The `-Zunstable-options --persist-doctests` flag is required, to save the test binaries
-(with their coverage maps) for `llvm-cov`.
-
-```bash
-$ cargo cov -- report \
-    $( \
-      for file in \
-        $( \
-          RUSTFLAGS="-Zinstrument-coverage" \
-          RUSTDOCFLAGS="-Zinstrument-coverage -Zunstable-options --persist-doctests target/debug/doctestbins" \
-            cargo test --no-run --message-format=json \
-              | jq -r "select(.profile.test == true) | .filenames[]" \
-              | grep -v dSYM - \
-        ) \
-        target/debug/doctestbins/*/rust_out; \
-      do \
-        [[ -x $file ]] && printf "%s %s " -object $file; \
-      done \
-    ) \
-  --instr-profile=json5format.profdata --summary-only # and/or other options
-```
-
-Note, the differences in this `cargo cov` command, compared with the version without
-doc tests, include:
-
-* The `cargo test ... --no-run` command is updated with the same environment variables
-  and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE`
-  is only used when _running_ the tests.)
-* The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out`
-  binaries generated for doc tests (note, however, that some `rust_out` files may not
-  be executable binaries).
-* `[[ -x $file ]] &&` filters the files passed on to the `printf`, to include only
-  executable binaries.
-
-[^79417]: There is ongoing work to resolve a known issue
-[(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage
-generates incorrect source line numbers in `llvm-cov show` results.
-
-## Other references
-
-Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.)
-
-[#79121]: https://github.com/rust-lang/rust/issues/79121
-[`-Zprofile`]: profile.md
-[`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic
-[LLVM Code Coverage Mapping Format]: https://llvm.org/docs/CoverageMappingFormat.html
-[rustc-dev-guide-how-to-build-and-run]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
-[`rustfilt`]: https://crates.io/crates/rustfilt
-[`json5format`]: https://crates.io/crates/json5format
-[`cargo-binutils`]: https://crates.io/crates/cargo-binutils
-[`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge
-[`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report
-[`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show
-[source-based code coverage in Clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+[`-z instrument-coverage`]: ./instrument-coverage.html
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md
new file mode 100644
index 00000000000..1757673612c
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md
@@ -0,0 +1,18 @@
+# `native_link_modifiers_as_needed`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_as_needed` feature allows you to use the `as-needed` modifier.
+
+`as-needed` is only compatible with the `dynamic` and `framework` linking kinds. Using any other kind will result in a compiler error.
+
+`+as-needed` means that the library will be actually linked only if it satisfies some undefined symbols at the point at which it is specified on the command line, making it similar to static libraries in this regard.
+
+This modifier translates to `--as-needed` for ld-like linkers, and to `-dead_strip_dylibs` / `-needed_library` / `-needed_framework` for ld64.
+The modifier does nothing for linkers that don't support it (e.g. `link.exe`).
+
+The default for this modifier is unclear, some targets currently specify it as `+as-needed`, some do not. We may want to try making `+as-needed` a default for all targets.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md
new file mode 100644
index 00000000000..ac192cff13a
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md
@@ -0,0 +1,19 @@
+# `native_link_modifiers_bundle`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_bundle` feature allows you to use the `bundle` modifier.
+
+Only compatible with the `static` linking kind. Using any other kind will result in a compiler error.
+
+`+bundle` means objects from the static library are bundled into the produced crate (a rlib, for example) and are used from this crate later during linking of the final binary.
+
+`-bundle` means the static library is included into the produced rlib "by name" and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking.
+
+This modifier is supposed to supersede the `static-nobundle` linking kind defined by [RFC 1717](https://github.com/rust-lang/rfcs/pull/1717).
+
+The default for this modifier is currently `+bundle`, but it could be changed later on some future edition boundary.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md
new file mode 100644
index 00000000000..02bd87e5095
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md
@@ -0,0 +1,20 @@
+# `native_link_modifiers_verbatim`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_verbatim` feature allows you to use the `verbatim` modifier.
+
+`+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker.
+
+For `ld`-like linkers rustc will use the `-l:filename` syntax (note the colon) when passing the library, so the linker won't add any prefixes or suffixes as well.
+See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in ld documentation for more details.
+For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`) the library name will be passed as is.
+
+The default for this modifier is `-verbatim`.
+
+This RFC changes the behavior of `raw-dylib` linking kind specified by [RFC 2627](https://github.com/rust-lang/rfcs/pull/2627). The `.dll` suffix (or other target-specified suffixes for other targets) is now added automatically.
+If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md
new file mode 100644
index 00000000000..4961e88cad1
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md
@@ -0,0 +1,18 @@
+# `native_link_modifiers_whole_archive`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_whole_archive` feature allows you to use the `whole-archive` modifier.
+
+Only compatible with the `static` linking kind. Using any other kind will result in a compiler error.
+
+`+whole-archive` means that the static library is linked as a whole archive without throwing any object files away.
+
+This modifier translates to `--whole-archive` for `ld`-like linkers, to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
+The modifier does nothing for linkers that don't support it.
+
+The default for this modifier is `-whole-archive`.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers.md b/src/doc/unstable-book/src/language-features/native-link-modifiers.md
new file mode 100644
index 00000000000..fc8b5754621
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/native-link-modifiers.md
@@ -0,0 +1,11 @@
+# `native_link_modifiers`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers` feature allows you to use the `modifiers` syntax with the `#[link(..)]` attribute.
+
+Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. The last boolean value specified for a given modifier wins.
diff --git a/src/doc/unstable-book/src/language-features/no-coverage.md b/src/doc/unstable-book/src/language-features/no-coverage.md
new file mode 100644
index 00000000000..327cdb39791
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/no-coverage.md
@@ -0,0 +1,30 @@
+# `no_coverage`
+
+The tracking issue for this feature is: [#84605]
+
+[#84605]: https://github.com/rust-lang/rust/issues/84605
+
+---
+
+The `no_coverage` attribute can be used to selectively disable coverage
+instrumentation in an annotated function. This might be useful to:
+
+-   Avoid instrumentation overhead in a performance critical function
+-   Avoid generating coverage for a function that is not meant to be executed,
+    but still target 100% coverage for the rest of the program.
+
+## Example
+
+```rust
+#![feature(no_coverage)]
+
+// `foo()` will get coverage instrumentation (by default)
+fn foo() {
+  // ...
+}
+
+#[no_coverage]
+fn bar() {
+  // ...
+}
+```
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index dbdf2e4bbb0..3bfc9fea62e 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -113,7 +113,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
             name: None,
             attrs: Default::default(),
             visibility: Inherited,
-            def_id: self.cx.next_def_id(item_def_id.krate),
+            def_id: FakeDefId::new_fake(item_def_id.krate),
             kind: box ImplItem(Impl {
                 span: Span::dummy(),
                 unsafety: hir::Unsafety::Normal,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index f5c4034a61d..68856f82fe9 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -97,7 +97,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     name: None,
                     attrs: Default::default(),
                     visibility: Inherited,
-                    def_id: self.cx.next_def_id(impl_def_id.krate),
+                    def_id: FakeDefId::new_fake(item_def_id.krate),
                     kind: box ImplItem(Impl {
                         span: self.cx.tcx.def_span(impl_def_id).clean(self.cx),
                         unsafety: hir::Unsafety::Normal,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 5dd9f3f1ebd..5974cd878dd 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -15,11 +15,11 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
-use crate::clean::{self, Attributes, AttributesExt, GetDefId, ToSource};
+use crate::clean::{self, Attributes, AttributesExt, FakeDefId, GetDefId, ToSource};
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 
-use super::Clean;
+use super::{Clean, Visibility};
 
 type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
 
@@ -121,7 +121,7 @@ crate fn try_inline(
     };
 
     let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
-    cx.inlined.insert(did);
+    cx.inlined.insert(did.into());
     ret.push(clean::Item::from_def_id_and_attrs_and_parts(
         did,
         Some(name),
@@ -188,13 +188,23 @@ crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemType)
     if did.is_local() {
         cx.cache.exact_paths.insert(did, fqn);
     } else {
-        cx.cache.external_paths.insert(did, (fqn, ItemType::from(kind)));
+        cx.cache.external_paths.insert(did, (fqn, kind));
     }
 }
 
 crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
-    let trait_items =
-        cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
+    let trait_items = cx
+        .tcx
+        .associated_items(did)
+        .in_definition_order()
+        .map(|item| {
+            // When building an external trait, the cleaned trait will have all items public,
+            // which causes methods to have a `pub` prefix, which is invalid since items in traits
+            // can not have a visibility prefix. Thus we override the visibility here manually.
+            // See https://github.com/rust-lang/rust/issues/81274
+            clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
+        })
+        .collect();
 
     let predicates = cx.tcx.predicates_of(did);
     let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
@@ -322,7 +332,7 @@ crate fn build_impl(
     attrs: Option<Attrs<'_>>,
     ret: &mut Vec<clean::Item>,
 ) {
-    if !cx.inlined.insert(did) {
+    if !cx.inlined.insert(did.into()) {
         return;
     }
 
@@ -460,7 +470,7 @@ fn build_module(
                 items.push(clean::Item {
                     name: None,
                     attrs: box clean::Attributes::default(),
-                    def_id: cx.next_def_id(did.krate),
+                    def_id: FakeDefId::new_fake(did.krate),
                     visibility: clean::Public,
                     kind: box clean::ImportItem(clean::Import::new_simple(
                         item.ident.name,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 39ff18e8bf5..411cfab9f06 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -17,11 +17,11 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
-use rustc_middle::bug;
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_mir::const_eval::{is_const_fn, is_unstable_const_fn};
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -100,12 +100,13 @@ impl Clean<Item> for doctree::Module<'_> {
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
         let span = Span::from_rustc_span({
+            let where_outer = self.where_outer(cx.tcx);
             let sm = cx.sess().source_map();
-            let outer = sm.lookup_char_pos(self.where_outer.lo());
+            let outer = sm.lookup_char_pos(where_outer.lo());
             let inner = sm.lookup_char_pos(self.where_inner.lo());
             if outer.file.start_pos == inner.file.start_pos {
                 // mod foo { ... }
-                self.where_outer
+                where_outer
             } else {
                 // mod foo; (and a separate SourceFile for the contents)
                 self.where_inner
@@ -157,7 +158,15 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
 impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
     fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         let (trait_ref, bounds) = *self;
-        inline::record_extern_fqn(cx, trait_ref.def_id, ItemType::Trait);
+        let kind = cx.tcx.def_kind(trait_ref.def_id).into();
+        if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
+            span_bug!(
+                cx.tcx.def_span(trait_ref.def_id),
+                "`TraitRef` had unexpected kind {:?}",
+                kind
+            );
+        }
+        inline::record_extern_fqn(cx, trait_ref.def_id, kind);
         let path = external_path(
             cx,
             cx.tcx.item_name(trait_ref.def_id),
@@ -524,7 +533,8 @@ impl Clean<Generics> for hir::Generics<'_> {
                 match param.kind {
                     GenericParamDefKind::Lifetime => unreachable!(),
                     GenericParamDefKind::Type { did, ref bounds, .. } => {
-                        cx.impl_trait_bounds.insert(did.into(), bounds.clone());
+                        cx.impl_trait_bounds
+                            .insert(FakeDefId::new_real(did).into(), bounds.clone());
                     }
                     GenericParamDefKind::Const { .. } => unreachable!(),
                 }
@@ -605,7 +615,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
             .collect::<Vec<GenericParamDef>>();
 
         // param index -> [(DefId of trait, associated type name, type)]
-        let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
+        let mut impl_trait_proj = FxHashMap::<u32, Vec<(FakeDefId, Symbol, Ty<'tcx>)>>::default();
 
         let where_predicates = preds
             .predicates
@@ -654,10 +664,11 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
                         if let Some(((_, trait_did, name), rhs)) =
                             proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
                         {
-                            impl_trait_proj
-                                .entry(param_idx)
-                                .or_default()
-                                .push((trait_did, name, rhs));
+                            impl_trait_proj.entry(param_idx).or_default().push((
+                                trait_did.into(),
+                                name,
+                                rhs,
+                            ));
                         }
 
                         return None;
@@ -676,7 +687,13 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
                 if let Some(proj) = impl_trait_proj.remove(&idx) {
                     for (trait_did, name, rhs) in proj {
                         let rhs = rhs.clean(cx);
-                        simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+                        simplify::merge_bounds(
+                            cx,
+                            &mut bounds,
+                            trait_did.expect_real(),
+                            name,
+                            &rhs,
+                        );
                     }
                 }
             } else {
@@ -1166,7 +1183,8 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 if let Some(new_ty) = cx.ty_substs.get(&did).cloned() {
                     return new_ty;
                 }
-                if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
+                if let Some(bounds) = cx.impl_trait_bounds.remove(&FakeDefId::new_real(did).into())
+                {
                     return ImplTrait(bounds);
                 }
             }
@@ -1997,7 +2015,7 @@ fn clean_extern_crate(
     vec![Item {
         name: Some(name),
         attrs: box attrs.clean(cx),
-        def_id: crate_def_id,
+        def_id: crate_def_id.into(),
         visibility: krate.vis.clean(cx),
         kind: box ExternCrateItem { src: orig_name },
         cfg: attrs.cfg(cx.sess().diagnostic()),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 33cb11e539b..47dae63f1fd 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1,6 +1,5 @@
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::default::Default;
-use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::lazy::SyncOnceCell as OnceCell;
@@ -19,7 +18,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
 use rustc_index::vec::IndexVec;
@@ -49,7 +48,94 @@ use self::ItemKind::*;
 use self::SelfTy::*;
 use self::Type::*;
 
-thread_local!(crate static MAX_DEF_IDX: RefCell<FxHashMap<CrateNum, DefIndex>> = Default::default());
+crate type FakeDefIdSet = FxHashSet<FakeDefId>;
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
+crate enum FakeDefId {
+    Real(DefId),
+    Fake(DefIndex, CrateNum),
+}
+
+impl FakeDefId {
+    #[cfg(parallel_compiler)]
+    crate fn new_fake(crate: CrateNum) -> Self {
+        unimplemented!("")
+    }
+
+    #[cfg(not(parallel_compiler))]
+    crate fn new_fake(krate: CrateNum) -> Self {
+        thread_local!(static FAKE_DEF_ID_COUNTER: Cell<usize> = Cell::new(0));
+        let id = FAKE_DEF_ID_COUNTER.with(|id| {
+            let tmp = id.get();
+            id.set(tmp + 1);
+            tmp
+        });
+        Self::Fake(DefIndex::from(id), krate)
+    }
+
+    crate fn new_real(id: DefId) -> Self {
+        Self::Real(id)
+    }
+
+    #[inline]
+    crate fn is_local(self) -> bool {
+        match self {
+            FakeDefId::Real(id) => id.is_local(),
+            FakeDefId::Fake(_, krate) => krate == LOCAL_CRATE,
+        }
+    }
+
+    #[inline]
+    crate fn as_local(self) -> Option<LocalDefId> {
+        match self {
+            FakeDefId::Real(id) => id.as_local(),
+            FakeDefId::Fake(idx, krate) => {
+                (krate == LOCAL_CRATE).then(|| LocalDefId { local_def_index: idx })
+            }
+        }
+    }
+
+    #[inline]
+    crate fn expect_local(self) -> LocalDefId {
+        self.as_local()
+            .unwrap_or_else(|| panic!("FakeDefId::expect_local: `{:?}` isn't local", self))
+    }
+
+    #[inline]
+    crate fn expect_real(self) -> rustc_hir::def_id::DefId {
+        self.as_real().unwrap_or_else(|| panic!("FakeDefId::expect_real: `{:?}` isn't real", self))
+    }
+
+    #[inline]
+    crate fn as_real(self) -> Option<DefId> {
+        match self {
+            FakeDefId::Real(id) => Some(id),
+            FakeDefId::Fake(_, _) => None,
+        }
+    }
+
+    #[inline]
+    crate fn krate(self) -> CrateNum {
+        match self {
+            FakeDefId::Real(id) => id.krate,
+            FakeDefId::Fake(_, krate) => krate,
+        }
+    }
+
+    #[inline]
+    crate fn index(self) -> Option<DefIndex> {
+        match self {
+            FakeDefId::Real(id) => Some(id.index),
+            FakeDefId::Fake(_, _) => None,
+        }
+    }
+}
+
+impl From<DefId> for FakeDefId {
+    fn from(id: DefId) -> Self {
+        Self::Real(id)
+    }
+}
 
 #[derive(Clone, Debug)]
 crate struct Crate {
@@ -261,7 +347,7 @@ impl ExternalCrate {
 /// Anything with a source location and set of attributes and, optionally, a
 /// name. That is, anything that can be documented. This doesn't correspond
 /// directly to the AST's concept of an item; it's a strict superset.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 crate struct Item {
     /// The name of this item.
     /// Optional because not every item has a name, e.g. impls.
@@ -271,7 +357,7 @@ crate struct Item {
     /// Information about this item that is specific to what kind of item it is.
     /// E.g., struct vs enum vs function.
     crate kind: Box<ItemKind>,
-    crate def_id: DefId,
+    crate def_id: FakeDefId,
 
     crate cfg: Option<Arc<Cfg>>,
 }
@@ -280,21 +366,6 @@ crate struct Item {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Item, 48);
 
-impl fmt::Debug for Item {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
-
-        fmt.debug_struct("Item")
-            .field("name", &self.name)
-            .field("attrs", &self.attrs)
-            .field("kind", &self.kind)
-            .field("visibility", &self.visibility)
-            .field("def_id", def_id)
-            .field("cfg", &self.cfg)
-            .finish()
-    }
-}
-
 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
     Span::from_rustc_span(def_id.as_local().map_or_else(
         || tcx.def_span(def_id),
@@ -307,19 +378,19 @@ crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
 
 impl Item {
     crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
-        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id.expect_real()) }
     }
 
     crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
-        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id.expect_real()) }
     }
 
     crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
-        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id.expect_real()) }
     }
 
     crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
-        if self.is_fake() { false } else { tcx.get_attrs(self.def_id).inner_docs() }
+        if self.is_fake() { false } else { tcx.get_attrs(self.def_id.expect_real()).inner_docs() }
     }
 
     crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -334,7 +405,7 @@ impl Item {
         } else if self.is_fake() {
             Span::dummy()
         } else {
-            rustc_span(self.def_id, tcx)
+            rustc_span(self.def_id.expect_real(), tcx)
         }
     }
 
@@ -388,7 +459,7 @@ impl Item {
         debug!("name={:?}, def_id={:?}", name, def_id);
 
         Item {
-            def_id,
+            def_id: def_id.into(),
             kind: box kind,
             name,
             attrs,
@@ -412,9 +483,9 @@ impl Item {
             .map_or(&[][..], |v| v.as_slice())
             .iter()
             .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
-                match *did {
+                match did {
                     Some(did) => {
-                        if let Some((mut href, ..)) = href(did, cx) {
+                        if let Some((mut href, ..)) = href(did.expect_real(), cx) {
                             if let Some(ref fragment) = *fragment {
                                 href.push('#');
                                 href.push_str(fragment);
@@ -433,8 +504,8 @@ impl Item {
                     None => {
                         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) => {
+                            let url = match cx.cache().extern_locations.get(&self.def_id.krate()) {
+                                Some(&ExternalLocation::Local) => {
                                     if relative_to[0] == "std" {
                                         let depth = relative_to.len() - 1;
                                         "../".repeat(depth)
@@ -446,10 +517,9 @@ impl Item {
                                 Some(ExternalLocation::Remote(ref s)) => {
                                     format!("{}/std/", s.trim_end_matches('/'))
                                 }
-                                Some(ExternalLocation::Unknown) | None => format!(
-                                    "https://doc.rust-lang.org/{}/std/",
-                                    crate::doc_rust_lang_org_channel(),
-                                ),
+                                Some(ExternalLocation::Unknown) | None => {
+                                    "https://doc.rust-lang.org/nightly/std/".to_string()
+                                }
                             };
                             // This is a primitive so the url is done "by hand".
                             let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
@@ -473,7 +543,7 @@ impl Item {
     }
 
     crate fn is_crate(&self) -> bool {
-        self.is_mod() && self.def_id.index == CRATE_DEF_INDEX
+        self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
     }
 
     crate fn is_mod(&self) -> bool {
@@ -586,13 +656,8 @@ impl Item {
         }
     }
 
-    /// See the documentation for [`next_def_id()`].
-    ///
-    /// [`next_def_id()`]: DocContext::next_def_id()
     crate fn is_fake(&self) -> bool {
-        MAX_DEF_IDX.with(|m| {
-            m.borrow().get(&self.def_id.krate).map(|&idx| idx <= self.def_id.index).unwrap_or(false)
-        })
+        matches!(self.def_id, FakeDefId::Fake(_, _))
     }
 }
 
@@ -678,10 +743,6 @@ impl ItemKind {
             | KeywordItem(_) => [].iter(),
         }
     }
-
-    crate fn is_type_alias(&self) -> bool {
-        matches!(self, ItemKind::TypedefItem(..) | ItemKind::AssocTypeItem(..))
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -915,7 +976,7 @@ crate struct ItemLink {
     /// This may not be the same as `link` if there was a disambiguator
     /// in an intra-doc link (e.g. \[`fn@f`\])
     pub(crate) link_text: String,
-    pub(crate) did: Option<DefId>,
+    pub(crate) did: Option<FakeDefId>,
     /// The url fragment to append to the link
     pub(crate) fragment: Option<String>,
 }
@@ -1036,7 +1097,7 @@ impl Attributes {
             }
         }
 
-        let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
+        let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
             if let Some(value) = attr.doc_str() {
                 trace!("got doc_str={:?}", value);
                 let value = beautify_doc_string(value);
@@ -1656,7 +1717,7 @@ impl Type {
 impl Type {
     fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
         let t: PrimitiveType = match *self {
-            ResolvedPath { did, .. } => return Some(did),
+            ResolvedPath { did, .. } => return Some(did.into()),
             Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
             BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 7df8b442e5a..51a011cf197 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -16,6 +16,9 @@ use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::mem;
 
+#[cfg(test)]
+mod tests;
+
 crate fn krate(cx: &mut DocContext<'_>) -> Crate {
     use crate::visit_lib::LibEmbargoVisitor;
 
@@ -45,9 +48,9 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
                 // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
                 if it.is_extern_crate()
                     && (it.attrs.has_doc_flag(sym::masked)
-                        || cx.tcx.is_compiler_builtins(it.def_id.krate))
+                        || cx.tcx.is_compiler_builtins(it.def_id.krate()))
                 {
-                    cx.cache.masked_crates.insert(it.def_id.krate);
+                    cx.cache.masked_crates.insert(it.def_id.krate());
                 }
             }
         }
@@ -335,11 +338,27 @@ crate fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String>
 
 fn format_integer_with_underscore_sep(num: &str) -> String {
     let num_chars: Vec<_> = num.chars().collect();
-    let num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 };
+    let mut num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 };
+    let chunk_size = match num[num_start_index..].as_bytes() {
+        [b'0', b'b' | b'x', ..] => {
+            num_start_index += 2;
+            4
+        }
+        [b'0', b'o', ..] => {
+            num_start_index += 2;
+            let remaining_chars = num_chars.len() - num_start_index;
+            if remaining_chars <= 6 {
+                // don't add underscores to Unix permissions like 0755 or 100755
+                return num.to_string();
+            }
+            3
+        }
+        _ => 3,
+    };
 
     num_chars[..num_start_index]
         .iter()
-        .chain(num_chars[num_start_index..].rchunks(3).rev().intersperse(&['_']).flatten())
+        .chain(num_chars[num_start_index..].rchunks(chunk_size).rev().intersperse(&['_']).flatten())
         .collect()
 }
 
@@ -490,8 +509,6 @@ where
 }
 
 /// Find the nearest parent module of a [`DefId`].
-///
-/// **Panics if the item it belongs to [is fake][Item::is_fake].**
 crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
     if def_id.is_top_level_module() {
         // The crate root has no parent. Use it as the root instead.
@@ -525,14 +542,3 @@ crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool {
             && attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
     })
 }
-
-/// Return a channel suitable for using in a `doc.rust-lang.org/{channel}` format string.
-crate fn doc_rust_lang_org_channel() -> &'static str {
-    match env!("CFG_RELEASE_CHANNEL") {
-        "stable" => env!("CFG_RELEASE_NUM"),
-        "beta" => "beta",
-        "nightly" | "dev" => "nightly",
-        // custom build of rustdoc maybe? link to the stable docs just in case
-        _ => "",
-    }
-}
diff --git a/src/librustdoc/clean/utils/tests.rs b/src/librustdoc/clean/utils/tests.rs
new file mode 100644
index 00000000000..ebf4b495483
--- /dev/null
+++ b/src/librustdoc/clean/utils/tests.rs
@@ -0,0 +1,41 @@
+use super::*;
+
+#[test]
+fn int_format_decimal() {
+    assert_eq!(format_integer_with_underscore_sep("12345678"), "12_345_678");
+    assert_eq!(format_integer_with_underscore_sep("123"), "123");
+    assert_eq!(format_integer_with_underscore_sep("123459"), "123_459");
+    assert_eq!(format_integer_with_underscore_sep("-12345678"), "-12_345_678");
+    assert_eq!(format_integer_with_underscore_sep("-123"), "-123");
+    assert_eq!(format_integer_with_underscore_sep("-123459"), "-123_459");
+}
+
+#[test]
+fn int_format_hex() {
+    assert_eq!(format_integer_with_underscore_sep("0xab3"), "0xab3");
+    assert_eq!(format_integer_with_underscore_sep("0xa2345b"), "0xa2_345b");
+    assert_eq!(format_integer_with_underscore_sep("0xa2e6345b"), "0xa2e6_345b");
+    assert_eq!(format_integer_with_underscore_sep("-0xab3"), "-0xab3");
+    assert_eq!(format_integer_with_underscore_sep("-0xa2345b"), "-0xa2_345b");
+    assert_eq!(format_integer_with_underscore_sep("-0xa2e6345b"), "-0xa2e6_345b");
+}
+
+#[test]
+fn int_format_binary() {
+    assert_eq!(format_integer_with_underscore_sep("0o12345671"), "0o12_345_671");
+    assert_eq!(format_integer_with_underscore_sep("0o123"), "0o123");
+    assert_eq!(format_integer_with_underscore_sep("0o123451"), "0o123451");
+    assert_eq!(format_integer_with_underscore_sep("-0o12345671"), "-0o12_345_671");
+    assert_eq!(format_integer_with_underscore_sep("-0o123"), "-0o123");
+    assert_eq!(format_integer_with_underscore_sep("-0o123451"), "-0o123451");
+}
+
+#[test]
+fn int_format_octal() {
+    assert_eq!(format_integer_with_underscore_sep("0b101"), "0b101");
+    assert_eq!(format_integer_with_underscore_sep("0b101101011"), "0b1_0110_1011");
+    assert_eq!(format_integer_with_underscore_sep("0b01101011"), "0b0110_1011");
+    assert_eq!(format_integer_with_underscore_sep("-0b101"), "-0b101");
+    assert_eq!(format_integer_with_underscore_sep("-0b101101011"), "-0b1_0110_1011");
+    assert_eq!(format_integer_with_underscore_sep("-0b01101011"), "-0b0110_1011");
+}
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/core.rs b/src/librustdoc/core.rs
index 212aac0e5b4..7b0c0b66996 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -6,7 +6,7 @@ use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::HirId;
 use rustc_hir::{
     intravisit::{self, NestedVisitorMap, Visitor},
@@ -26,13 +26,11 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 
 use std::cell::RefCell;
-use std::collections::hash_map::Entry;
 use std::mem;
 use std::rc::Rc;
 
-use crate::clean;
 use crate::clean::inline::build_external_trait;
-use crate::clean::{TraitWithExtraInfo, MAX_DEF_IDX};
+use crate::clean::{self, FakeDefId, TraitWithExtraInfo};
 use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
 use crate::formats::cache::Cache;
 use crate::passes::{self, Condition::*, ConditionalPass};
@@ -66,7 +64,6 @@ crate struct DocContext<'tcx> {
     crate ct_substs: FxHashMap<DefId, clean::Constant>,
     /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
     crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
-    crate fake_def_ids: FxHashMap<CrateNum, DefIndex>,
     /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
     // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
     crate generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>,
@@ -81,7 +78,7 @@ crate struct DocContext<'tcx> {
     /// This same cache is used throughout rustdoc, including in [`crate::html::render`].
     crate cache: Cache,
     /// Used by [`clean::inline`] to tell if an item has already been inlined.
-    crate inlined: FxHashSet<DefId>,
+    crate inlined: FxHashSet<FakeDefId>,
     /// Used by `calculate_doc_coverage`.
     crate output_format: OutputFormat,
 }
@@ -129,54 +126,14 @@ impl<'tcx> DocContext<'tcx> {
         r
     }
 
-    /// Create a new "fake" [`DefId`].
-    ///
-    /// This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
-    /// refactoring either rustdoc or [`rustc_middle`]. In particular, allowing new [`DefId`]s
-    /// to be registered after the AST is constructed would require storing the [`DefId`] mapping
-    /// in a [`RefCell`], decreasing the performance for normal compilation for very little gain.
-    ///
-    /// Instead, we construct "fake" [`DefId`]s, which start immediately after the last `DefId`.
-    /// In the [`Debug`] impl for [`clean::Item`], we explicitly check for fake `DefId`s,
-    /// as we'll end up with a panic if we use the `DefId` `Debug` impl for fake `DefId`s.
-    ///
-    /// [`RefCell`]: std::cell::RefCell
-    /// [`Debug`]: std::fmt::Debug
-    /// [`clean::Item`]: crate::clean::types::Item
-    crate fn next_def_id(&mut self, crate_num: CrateNum) -> DefId {
-        let def_index = match self.fake_def_ids.entry(crate_num) {
-            Entry::Vacant(e) => {
-                let num_def_idx = {
-                    let num_def_idx = if crate_num == LOCAL_CRATE {
-                        self.tcx.hir().definitions().def_path_table().num_def_ids()
-                    } else {
-                        self.resolver.borrow_mut().access(|r| r.cstore().num_def_ids(crate_num))
-                    };
-
-                    DefIndex::from_usize(num_def_idx)
-                };
-
-                MAX_DEF_IDX.with(|m| {
-                    m.borrow_mut().insert(crate_num, num_def_idx);
-                });
-                e.insert(num_def_idx)
-            }
-            Entry::Occupied(e) => e.into_mut(),
-        };
-        *def_index = *def_index + 1;
-
-        DefId { krate: crate_num, index: *def_index }
-    }
-
     /// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
     /// (This avoids a slice-index-out-of-bounds panic.)
-    crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<HirId> {
-        if MAX_DEF_IDX.with(|m| {
-            m.borrow().get(&def_id.krate).map(|&idx| idx <= def_id.index).unwrap_or(false)
-        }) {
-            None
-        } else {
-            def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+    crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: FakeDefId) -> Option<HirId> {
+        match def_id {
+            FakeDefId::Real(real_id) => {
+                real_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+            }
+            FakeDefId::Fake(_, _) => None,
         }
     }
 }
@@ -419,7 +376,6 @@ crate fn run_global_ctxt(
         lt_substs: Default::default(),
         ct_substs: Default::default(),
         impl_trait_bounds: Default::default(),
-        fake_def_ids: Default::default(),
         generated_synthetics: Default::default(),
         auto_traits: tcx
             .all_traits(LOCAL_CRATE)
@@ -450,18 +406,15 @@ crate fn run_global_ctxt(
     let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
 
     if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
-        let help = format!(
-            "The following guide may be of use:\n\
-            https://doc.rust-lang.org/{}/rustdoc/how-to-write-documentation.html",
-            crate::doc_rust_lang_org_channel(),
-        );
+        let help = "The following guide may be of use:\n\
+                https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
         tcx.struct_lint_node(
             crate::lint::MISSING_CRATE_LEVEL_DOCS,
             DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
             |lint| {
                 let mut diag =
                     lint.build("no documentation found for this crate's top-level module");
-                diag.help(&help);
+                diag.help(help);
                 diag.emit();
             },
         );
@@ -630,12 +583,12 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
 /// for `impl Trait` in argument position.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 crate enum ImplTraitParam {
-    DefId(DefId),
+    DefId(FakeDefId),
     ParamIndex(u32),
 }
 
-impl From<DefId> for ImplTraitParam {
-    fn from(did: DefId) -> Self {
+impl From<FakeDefId> for ImplTraitParam {
+    fn from(did: FakeDefId) -> Self {
         ImplTraitParam::DefId(did)
     }
 }
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/doctree.rs b/src/librustdoc/doctree.rs
index d3f4353a58b..eadac89f79e 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -1,12 +1,12 @@
 //! This module is used to store stuff from Rust's AST in a more convenient
 //! manner (and with prettier names) before cleaning.
+use rustc_middle::ty::TyCtxt;
 use rustc_span::{self, Span, Symbol};
 
 use rustc_hir as hir;
 
 crate struct Module<'hir> {
     crate name: Symbol,
-    crate where_outer: Span,
     crate where_inner: Span,
     crate mods: Vec<Module<'hir>>,
     crate id: hir::HirId,
@@ -17,16 +17,19 @@ crate struct Module<'hir> {
 }
 
 impl Module<'hir> {
-    crate fn new(name: Symbol) -> Module<'hir> {
+    crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> {
         Module {
             name,
-            id: hir::CRATE_HIR_ID,
-            where_outer: rustc_span::DUMMY_SP,
-            where_inner: rustc_span::DUMMY_SP,
+            id,
+            where_inner,
             mods: Vec::new(),
             items: Vec::new(),
             foreigns: Vec::new(),
             macros: Vec::new(),
         }
     }
+
+    crate fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.hir().span(self.id)
+    }
 }
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 8723e47586e..50496f32009 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -8,7 +8,7 @@ use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
-use crate::clean::{self, GetDefId};
+use crate::clean::{self, FakeDefId, GetDefId};
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
@@ -67,7 +67,7 @@ crate struct Cache {
     /// When rendering traits, it's often useful to be able to list all
     /// implementors of the trait, and this mapping is exactly, that: a mapping
     /// of trait ids to the list of known implementors of the trait
-    crate implementors: FxHashMap<DefId, Vec<Impl>>,
+    crate implementors: FxHashMap<FakeDefId, Vec<Impl>>,
 
     /// Cache of where external crate documentation can be found.
     crate extern_locations: FxHashMap<CrateNum, ExternalLocation>,
@@ -122,7 +122,7 @@ crate struct Cache {
     /// All intra-doc links resolved so far.
     ///
     /// Links are indexed by the DefId of the item they document.
-    crate intra_doc_links: BTreeMap<DefId, Vec<clean::ItemLink>>,
+    crate intra_doc_links: BTreeMap<FakeDefId, Vec<clean::ItemLink>>,
 }
 
 /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
@@ -205,7 +205,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         // If the impl is from a masked crate or references something from a
         // masked crate then remove it completely.
         if let clean::ImplItem(ref i) = *item.kind {
-            if self.cache.masked_crates.contains(&item.def_id.krate)
+            if self.cache.masked_crates.contains(&item.def_id.krate())
                 || i.trait_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
                 || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
             {
@@ -216,9 +216,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         // Propagate a trait method's documentation to all implementors of the
         // trait.
         if let clean::TraitItem(ref t) = *item.kind {
-            self.cache.traits.entry(item.def_id).or_insert_with(|| clean::TraitWithExtraInfo {
-                trait_: t.clone(),
-                is_notable: item.attrs.has_doc_flag(sym::notable_trait),
+            self.cache.traits.entry(item.def_id.expect_real()).or_insert_with(|| {
+                clean::TraitWithExtraInfo {
+                    trait_: t.clone(),
+                    is_notable: item.attrs.has_doc_flag(sym::notable_trait),
+                }
             });
         }
 
@@ -228,7 +230,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                 if i.blanket_impl.is_none() {
                     self.cache
                         .implementors
-                        .entry(did)
+                        .entry(did.into())
                         .or_default()
                         .push(Impl { impl_item: item.clone() });
                 }
@@ -289,7 +291,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // A crate has a module at its root, containing all items,
                     // which should not be indexed. The crate-item itself is
                     // inserted later on when serializing the search-index.
-                    if item.def_id.index != CRATE_DEF_INDEX {
+                    if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
                         self.cache.search_index.push(IndexItem {
                             ty: item.type_(),
                             name: s.to_string(),
@@ -297,7 +299,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                             desc: item
                                 .doc_value()
                                 .map_or_else(String::new, |x| short_markdown_summary(&x.as_str())),
-                            parent,
+                            parent: parent.map(FakeDefId::new_real),
                             parent_idx: None,
                             search_type: get_index_search_type(&item, &self.empty_cache, self.tcx),
                             aliases: item.attrs.get_doc_aliases(),
@@ -327,6 +329,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             | clean::EnumItem(..)
             | clean::TypedefItem(..)
             | clean::TraitItem(..)
+            | clean::TraitAliasItem(..)
             | clean::FunctionItem(..)
             | clean::ModuleItem(..)
             | clean::ForeignFunctionItem(..)
@@ -337,26 +340,46 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             | clean::ForeignTypeItem
             | clean::MacroItem(..)
             | clean::ProcMacroItem(..)
-            | clean::VariantItem(..)
-                if !self.cache.stripped_mod =>
-            {
-                // Re-exported items mean that the same id can show up twice
-                // in the rustdoc ast that we're looking at. We know,
-                // however, that a re-exported item doesn't show up in the
-                // `public_items` map, so we can skip inserting into the
-                // paths map if there was already an entry present and we're
-                // not a public item.
-                if !self.cache.paths.contains_key(&item.def_id)
-                    || self.cache.access_levels.is_public(item.def_id)
-                {
-                    self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_()));
+            | clean::VariantItem(..) => {
+                if !self.cache.stripped_mod {
+                    // Re-exported items mean that the same id can show up twice
+                    // in the rustdoc ast that we're looking at. We know,
+                    // however, that a re-exported item doesn't show up in the
+                    // `public_items` map, so we can skip inserting into the
+                    // paths map if there was already an entry present and we're
+                    // not a public item.
+                    if !self.cache.paths.contains_key(&item.def_id.expect_real())
+                        || self.cache.access_levels.is_public(item.def_id.expect_real())
+                    {
+                        self.cache.paths.insert(
+                            item.def_id.expect_real(),
+                            (self.cache.stack.clone(), item.type_()),
+                        );
+                    }
                 }
             }
             clean::PrimitiveItem(..) => {
-                self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_()));
+                self.cache
+                    .paths
+                    .insert(item.def_id.expect_real(), (self.cache.stack.clone(), item.type_()));
             }
 
-            _ => {}
+            clean::ExternCrateItem { .. }
+            | clean::ImportItem(..)
+            | clean::OpaqueTyItem(..)
+            | clean::ImplItem(..)
+            | clean::TyMethodItem(..)
+            | clean::MethodItem(..)
+            | clean::StructFieldItem(..)
+            | clean::AssocConstItem(..)
+            | clean::AssocTypeItem(..)
+            | clean::StrippedItem(..)
+            | clean::KeywordItem(..) => {
+                // FIXME: Do these need handling?
+                // The person writing this comment doesn't know.
+                // So would rather leave them to an expert,
+                // as at least the list is better than `_ => {}`.
+            }
         }
 
         // Maintain the parent stack
@@ -368,7 +391,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             | clean::StructItem(..)
             | clean::UnionItem(..)
             | clean::VariantItem(..) => {
-                self.cache.parent_stack.push(item.def_id);
+                self.cache.parent_stack.push(item.def_id.expect_real());
                 self.cache.parent_is_trait_impl = false;
                 true
             }
diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs
index 1ce6572bbed..6060b0560cf 100644
--- a/src/librustdoc/formats/mod.rs
+++ b/src/librustdoc/formats/mod.rs
@@ -2,9 +2,9 @@ crate mod cache;
 crate mod item_type;
 crate mod renderer;
 
-crate use renderer::{run_format, FormatRenderer};
+use rustc_hir::def_id::DefId;
 
-use rustc_span::def_id::DefId;
+crate use renderer::{run_format, FormatRenderer};
 
 use crate::clean;
 use crate::clean::types::GetDefId;
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index f211a5acf5e..fa57c9bda74 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -12,11 +12,14 @@ use std::iter;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_target::spec::abi::Abi;
 
-use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, PrimitiveType};
+use crate::clean::{
+    self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, PrimitiveType,
+};
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::render::cache::ExternalLocation;
@@ -637,7 +640,7 @@ crate fn anchor<'a, 'cx: 'a>(
     text: &'a str,
     cx: &'cx Context<'_>,
 ) -> impl fmt::Display + 'a {
-    let parts = href(did, cx);
+    let parts = href(did.into(), cx);
     display_fn(move |f| {
         if let Some((url, short_ty, fqp)) = parts {
             write!(
@@ -865,7 +868,7 @@ fn fmt_type<'cx>(
                 //        everything comes in as a fully resolved QPath (hard to
                 //        look at).
                 box clean::ResolvedPath { did, ref param_names, .. } => {
-                    match href(did, cx) {
+                    match href(did.into(), cx) {
                         Some((ref url, _, ref path)) if !f.alternate() => {
                             write!(
                                 f,
@@ -1143,7 +1146,7 @@ impl clean::FnDecl {
 impl clean::Visibility {
     crate fn print_with_space<'a, 'tcx: 'a>(
         self,
-        item_did: DefId,
+        item_did: FakeDefId,
         cx: &'a Context<'tcx>,
     ) -> impl fmt::Display + 'a + Captures<'tcx> {
         let to_print = match self {
@@ -1153,7 +1156,7 @@ impl clean::Visibility {
                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
                 //                 However, rustdoc currently never displays a module's
                 //                 visibility, so it shouldn't matter.
-                let parent_module = find_nearest_parent_module(cx.tcx(), item_did);
+                let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_real());
 
                 if vis_did.index == CRATE_DEF_INDEX {
                     "pub(crate) ".to_owned()
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 0030ef67c07..f631f627fc2 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -13,7 +13,6 @@ use std::iter::Peekable;
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
-use rustc_span::with_default_session_globals;
 
 use super::format::Buffer;
 
@@ -46,7 +45,7 @@ crate fn render_with_highlighting(
 }
 
 fn write_header(out: &mut Buffer, class: Option<&str>) {
-    write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or_default());
+    writeln!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">", class.unwrap_or_default());
 }
 
 fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
@@ -62,7 +61,7 @@ fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
-    write!(out, "</pre>{}</div>\n", playground_button.unwrap_or_default());
+    writeln!(out, "</pre>{}</div>", playground_button.unwrap_or_default());
 }
 
 /// How a span of text is classified. Mostly corresponds to token kinds.
@@ -238,28 +237,26 @@ impl<'a> Classifier<'a> {
     /// possibly giving it an HTML span with a class specifying what flavor of
     /// token is used.
     fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
-        with_default_session_globals(|| {
-            loop {
-                if self
-                    .tokens
-                    .peek()
-                    .map(|t| matches!(t.0, TokenKind::Colon | TokenKind::Ident))
-                    .unwrap_or(false)
-                {
-                    let tokens = self.get_full_ident_path();
-                    for (token, start, end) in tokens {
-                        let text = &self.src[start..end];
-                        self.advance(token, text, sink);
-                        self.byte_pos += text.len() as u32;
-                    }
-                }
-                if let Some((token, text)) = self.next() {
+        loop {
+            if self
+                .tokens
+                .peek()
+                .map(|t| matches!(t.0, TokenKind::Colon | TokenKind::Ident))
+                .unwrap_or(false)
+            {
+                let tokens = self.get_full_ident_path();
+                for (token, start, end) in tokens {
+                    let text = &self.src[start..end];
                     self.advance(token, text, sink);
-                } else {
-                    break;
+                    self.byte_pos += text.len() as u32;
                 }
             }
-        })
+            if let Some((token, text)) = self.next() {
+                self.advance(token, text, sink);
+            } else {
+                break;
+            }
+        }
     }
 
     /// Single step of highlighting. This will classify `token`, but maybe also
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 305cf61091d..a0da2c963d1 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -2,6 +2,7 @@ use super::write_code;
 use crate::html::format::Buffer;
 use expect_test::expect_file;
 use rustc_span::edition::Edition;
+use rustc_span::with_default_session_globals;
 
 const STYLE: &str = r#"
 <style>
@@ -17,21 +18,25 @@ const STYLE: &str = r#"
 
 #[test]
 fn test_html_highlighting() {
-    let src = include_str!("fixtures/sample.rs");
-    let html = {
-        let mut out = Buffer::new();
-        write_code(&mut out, src, Edition::Edition2018);
-        format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
-    };
-    expect_file!["fixtures/sample.html"].assert_eq(&html);
+    with_default_session_globals(|| {
+        let src = include_str!("fixtures/sample.rs");
+        let html = {
+            let mut out = Buffer::new();
+            write_code(&mut out, src, Edition::Edition2018);
+            format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
+        };
+        expect_file!["fixtures/sample.html"].assert_eq(&html);
+    });
 }
 
 #[test]
 fn test_dos_backline() {
-    let src = "pub fn foo() {\r\n\
+    with_default_session_globals(|| {
+        let src = "pub fn foo() {\r\n\
     println!(\"foo\");\r\n\
 }\r\n";
-    let mut html = Buffer::new();
-    write_code(&mut html, src, Edition::Edition2018);
-    expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
+        let mut html = Buffer::new();
+        write_code(&mut html, src, Edition::Edition2018);
+        expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
+    });
 }
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 27a8065afb6..57520a1a1fb 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -7,7 +7,7 @@ use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
 use crate::clean::types::{
-    FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
+    FakeDefId, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
 };
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
@@ -39,7 +39,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
                 name: item.name.unwrap().to_string(),
                 path: fqp[..fqp.len() - 1].join("::"),
                 desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
-                parent: Some(did),
+                parent: Some(did.into()),
                 parent_idx: None,
                 search_type: get_index_search_type(&item, cache, tcx),
                 aliases: item.attrs.get_doc_aliases(),
@@ -82,7 +82,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
                 defid_to_pathid.insert(defid, pathid);
                 lastpathid += 1;
 
-                if let Some(&(ref fqp, short)) = paths.get(&defid) {
+                if let Some(&(ref fqp, short)) = paths.get(&defid.expect_real()) {
                     crate_paths.push((short, fqp.last().unwrap().clone()));
                     Some(pathid)
                 } else {
@@ -214,7 +214,7 @@ crate fn get_index_search_type<'tcx>(
 
 fn get_index_type(clean_type: &clean::Type, cache: &Cache) -> RenderType {
     RenderType {
-        ty: clean_type.def_id_full(cache),
+        ty: clean_type.def_id_full(cache).map(FakeDefId::new_real),
         idx: None,
         name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
         generics: get_generics(clean_type, cache),
@@ -256,7 +256,7 @@ fn get_generics(clean_type: &clean::Type, cache: &Cache) -> Option<Vec<Generic>>
             .filter_map(|t| {
                 get_index_type_name(t, false).map(|name| Generic {
                     name: name.as_str().to_ascii_lowercase(),
-                    defid: t.def_id_full(cache),
+                    defid: t.def_id_full(cache).map(FakeDefId::new_real),
                     idx: None,
                 })
             })
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 293c0a40fa7..2f3f87215c3 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -18,7 +18,8 @@ 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::{self, ExternalCrate};
+use crate::clean;
+use crate::clean::ExternalCrate;
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
@@ -218,7 +219,7 @@ impl<'tcx> Context<'tcx> {
                 &self.shared.style_files,
             )
         } else {
-            if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
+            if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id.expect_real()) {
                 let mut path = String::new();
                 for name in &names[..names.len() - 1] {
                     path.push_str(name);
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 0a8026ef942..ea57831c0e5 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -54,7 +54,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
 
-use crate::clean::{self, GetDefId, RenderedLink, SelfTy};
+use crate::clean::{self, FakeDefId, GetDefId, RenderedLink, SelfTy};
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
@@ -87,7 +87,7 @@ crate struct IndexItem {
     crate name: String,
     crate path: String,
     crate desc: String,
-    crate parent: Option<DefId>,
+    crate parent: Option<FakeDefId>,
     crate parent_idx: Option<usize>,
     crate search_type: Option<IndexItemFunctionType>,
     crate aliases: Box<[String]>,
@@ -96,7 +96,7 @@ crate struct IndexItem {
 /// A type used for the search index.
 #[derive(Debug)]
 crate struct RenderType {
-    ty: Option<DefId>,
+    ty: Option<FakeDefId>,
     idx: Option<usize>,
     name: Option<String>,
     generics: Option<Vec<Generic>>,
@@ -128,7 +128,7 @@ impl Serialize for RenderType {
 #[derive(Debug)]
 crate struct Generic {
     name: String,
-    defid: Option<DefId>,
+    defid: Option<FakeDefId>,
     idx: Option<usize>,
 }
 
@@ -508,23 +508,16 @@ fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option
     if let Some(ref name) = item.name {
         info!("Documenting {}", name);
     }
-    document_item_info(w, cx, item, false, parent);
-    document_full(w, item, cx, false);
+    document_item_info(w, cx, item, parent);
+    document_full(w, item, cx);
 }
 
 /// Render md_text as markdown.
-fn render_markdown(
-    w: &mut Buffer,
-    cx: &Context<'_>,
-    md_text: &str,
-    links: Vec<RenderedLink>,
-    is_hidden: bool,
-) {
+fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec<RenderedLink>) {
     let mut ids = cx.id_map.borrow_mut();
     write!(
         w,
-        "<div class=\"docblock{}\">{}</div>",
-        if is_hidden { " hidden" } else { "" },
+        "<div class=\"docblock\">{}</div>",
         Markdown(
             md_text,
             &links,
@@ -544,11 +537,10 @@ fn document_short(
     item: &clean::Item,
     cx: &Context<'_>,
     link: AssocItemLink<'_>,
-    is_hidden: bool,
     parent: &clean::Item,
     show_def_docs: bool,
 ) {
-    document_item_info(w, cx, item, is_hidden, Some(parent));
+    document_item_info(w, cx, item, Some(parent));
     if !show_def_docs {
         return;
     }
@@ -565,19 +557,14 @@ fn document_short(
             }
         }
 
-        write!(
-            w,
-            "<div class='docblock{}'>{}</div>",
-            if is_hidden { " hidden" } else { "" },
-            summary_html,
-        );
+        write!(w, "<div class='docblock'>{}</div>", summary_html,);
     }
 }
 
-fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_hidden: bool) {
+fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
         debug!("Doc block: =====\n{}\n=====", s);
-        render_markdown(w, cx, &s, item.links(cx), is_hidden);
+        render_markdown(w, cx, &s, item.links(cx));
     }
 }
 
@@ -590,16 +577,11 @@ fn document_item_info(
     w: &mut Buffer,
     cx: &Context<'_>,
     item: &clean::Item,
-    is_hidden: bool,
     parent: Option<&clean::Item>,
 ) {
     let item_infos = short_item_info(item, cx, parent);
     if !item_infos.is_empty() {
-        if is_hidden {
-            w.write_str("<div class=\"item-info hidden\">");
-        } else {
-            w.write_str("<div class=\"item-info\">");
-        }
+        w.write_str("<div class=\"item-info\">");
         for info in item_infos {
             w.write_str(&info);
         }
@@ -727,7 +709,7 @@ fn render_impls(
         .map(|i| {
             let did = i.trait_did_full(cache).unwrap();
             let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
-            let assoc_link = AssocItemLink::GotoSource(did, &provided_trait_methods);
+            let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
             render_impl(
                 &mut buffer,
@@ -765,7 +747,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
         AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
         AssocItemLink::Anchor(None) => anchor,
         AssocItemLink::GotoSource(did, _) => {
-            href(did, cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
+            href(did.expect_real(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
         }
     }
 }
@@ -873,7 +855,7 @@ fn render_assoc_item(
                     ItemType::TyMethod
                 };
 
-                href(did, cx)
+                href(did.expect_real(), cx)
                     .map(|p| format!("{}#{}.{}", p.0, ty, name))
                     .unwrap_or_else(|| format!("#{}.{}", ty, name))
             }
@@ -982,7 +964,7 @@ fn attributes(it: &clean::Item) -> Vec<String> {
 // a whitespace prefix and newline.
 fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
     for a in attributes(it) {
-        write!(w, "{}{}\n", prefix, a);
+        writeln!(w, "{}{}", prefix, a);
     }
 }
 
@@ -997,7 +979,7 @@ fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
-    GotoSource(DefId, &'a FxHashSet<Symbol>),
+    GotoSource(FakeDefId, &'a FxHashSet<Symbol>),
 }
 
 impl<'a> AssocItemLink<'a> {
@@ -1235,7 +1217,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
                                 it,
                                 &[],
                                 Some(&tydef.type_),
-                                AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
+                                AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()),
                                 "",
                                 cx,
                             );
@@ -1282,8 +1264,12 @@ fn render_impl(
     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
     let mut close_tags = String::new();
 
+    // For trait implementations, the `interesting` output contains all methods that have doc
+    // comments, and the `boring` output contains all methods that do not. The distinction is
+    // used to allow hiding the boring methods.
     fn doc_impl_item(
-        w: &mut Buffer,
+        boring: &mut Buffer,
+        interesting: &mut Buffer,
         cx: &Context<'_>,
         item: &clean::Item,
         parent: &clean::Item,
@@ -1306,15 +1292,46 @@ fn render_impl(
             }
         };
 
-        let (is_hidden, extra_class) =
-            if (trait_.is_none() || item.doc_value().is_some() || item.kind.is_type_alias())
-                && !is_default_item
-            {
-                (false, "")
-            } else {
-                (true, " hidden")
-            };
         let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
+
+        let mut doc_buffer = Buffer::empty_from(boring);
+        let mut info_buffer = Buffer::empty_from(boring);
+        let mut short_documented = true;
+
+        if render_method_item {
+            if !is_default_item {
+                if let Some(t) = trait_ {
+                    // The trait item may have been stripped so we might not
+                    // find any documentation or stability for it.
+                    if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
+                        // We need the stability of the item from the trait
+                        // because impls can't have a stability.
+                        if item.doc_value().is_some() {
+                            document_item_info(&mut info_buffer, cx, it, Some(parent));
+                            document_full(&mut doc_buffer, item, cx);
+                            short_documented = false;
+                        } else {
+                            // In case the item isn't documented,
+                            // provide short documentation from the trait.
+                            document_short(&mut doc_buffer, it, cx, link, parent, show_def_docs);
+                        }
+                    }
+                } else {
+                    document_item_info(&mut info_buffer, cx, item, Some(parent));
+                    if show_def_docs {
+                        document_full(&mut doc_buffer, item, cx);
+                        short_documented = false;
+                    }
+                }
+            } else {
+                document_short(&mut doc_buffer, item, cx, link, parent, show_def_docs);
+            }
+        }
+        let w = if short_documented && trait_.is_some() { interesting } else { boring };
+
+        if !doc_buffer.is_empty() {
+            w.write_str("<details class=\"rustdoc-toggle\" open><summary>");
+        }
         match *item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
                 // Only render when the method is not static or we allow static methods
@@ -1327,11 +1344,7 @@ fn render_impl(
                             })
                         })
                         .map(|item| format!("{}.{}", item.type_(), name));
-                    write!(
-                        w,
-                        "<h4 id=\"{}\" class=\"{}{}{}\">",
-                        id, item_type, extra_class, in_trait_class,
-                    );
+                    write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
                     w.write_str("<code>");
                     render_assoc_item(
                         w,
@@ -1356,11 +1369,7 @@ fn render_impl(
             clean::TypedefItem(ref tydef, _) => {
                 let source_id = format!("{}.{}", ItemType::AssocType, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
-                    id, item_type, extra_class, in_trait_class
-                );
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
                 assoc_type(
                     w,
                     item,
@@ -1377,11 +1386,7 @@ fn render_impl(
             clean::AssocConstItem(ref ty, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
-                    id, item_type, extra_class, in_trait_class
-                );
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
                 assoc_const(
                     w,
                     item,
@@ -1406,11 +1411,7 @@ fn render_impl(
             clean::AssocTypeItem(ref bounds, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
-                    id, item_type, extra_class, in_trait_class
-                );
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
                 assoc_type(
                     w,
                     item,
@@ -1428,38 +1429,20 @@ fn render_impl(
             _ => panic!("can't make docs for trait item with name {:?}", item.name),
         }
 
-        if render_method_item {
-            if !is_default_item {
-                if let Some(t) = trait_ {
-                    // The trait item may have been stripped so we might not
-                    // find any documentation or stability for it.
-                    if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
-                        // We need the stability of the item from the trait
-                        // because impls can't have a stability.
-                        if item.doc_value().is_some() {
-                            document_item_info(w, cx, it, is_hidden, Some(parent));
-                            document_full(w, item, cx, is_hidden);
-                        } else {
-                            // In case the item isn't documented,
-                            // provide short documentation from the trait.
-                            document_short(w, it, cx, link, is_hidden, parent, show_def_docs);
-                        }
-                    }
-                } else {
-                    document_item_info(w, cx, item, is_hidden, Some(parent));
-                    if show_def_docs {
-                        document_full(w, item, cx, is_hidden);
-                    }
-                }
-            } else {
-                document_short(w, item, cx, link, is_hidden, parent, show_def_docs);
-            }
+        w.push_buffer(info_buffer);
+        if !doc_buffer.is_empty() {
+            w.write_str("</summary>");
+            w.push_buffer(doc_buffer);
+            w.push_str("</details>");
         }
     }
 
     let mut impl_items = Buffer::empty_from(w);
+    let mut default_impl_items = Buffer::empty_from(w);
+
     for trait_item in &i.inner_impl().items {
         doc_impl_item(
+            &mut default_impl_items,
             &mut impl_items,
             cx,
             trait_item,
@@ -1475,7 +1458,8 @@ fn render_impl(
     }
 
     fn render_default_items(
-        w: &mut Buffer,
+        boring: &mut Buffer,
+        interesting: &mut Buffer,
         cx: &Context<'_>,
         t: &clean::Trait,
         i: &clean::Impl,
@@ -1492,10 +1476,11 @@ fn render_impl(
             }
             let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
             let provided_methods = i.provided_trait_methods(cx.tcx());
-            let assoc_link = AssocItemLink::GotoSource(did, &provided_methods);
+            let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
 
             doc_impl_item(
-                w,
+                boring,
+                interesting,
                 cx,
                 trait_item,
                 parent,
@@ -1517,6 +1502,7 @@ fn render_impl(
     if show_default_items {
         if let Some(t) = trait_ {
             render_default_items(
+                &mut default_impl_items,
                 &mut impl_items,
                 cx,
                 &t.trait_,
@@ -1529,10 +1515,14 @@ fn render_impl(
             );
         }
     }
-    let details_str = if impl_items.is_empty() {
-        ""
-    } else {
-        "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+    let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
+    let open_details = |close_tags: &mut String| {
+        if toggled {
+            close_tags.insert_str(0, "</details>");
+            "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+        } else {
+            ""
+        }
     };
     if render_mode == RenderMode::Normal {
         let id = cx.derive_id(match i.inner_impl().trait_ {
@@ -1554,11 +1544,10 @@ fn render_impl(
             write!(
                 w,
                 "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
-                details_str, id, aliases
+                open_details(&mut close_tags),
+                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 {
@@ -1582,14 +1571,11 @@ fn render_impl(
             write!(
                 w,
                 "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
-                details_str,
+                open_details(&mut close_tags),
                 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(
@@ -1600,7 +1586,7 @@ fn render_impl(
             outer_const_version,
         );
         write_srclink(cx, &i.impl_item, w);
-        if impl_items.is_empty() {
+        if !toggled {
             w.write_str("</h3>");
         } else {
             w.write_str("</h3></summary>");
@@ -1629,8 +1615,13 @@ fn render_impl(
             );
         }
     }
-    if !impl_items.is_empty() {
+    if toggled {
         w.write_str("<div class=\"impl-items\">");
+        w.push_buffer(default_impl_items);
+        if trait_.is_some() && !impl_items.is_empty() {
+            w.write_str("<details class=\"undocumented\"><summary></summary>");
+            close_tags.insert_str(0, "</details>");
+        }
         w.push_buffer(impl_items);
         close_tags.insert_str(0, "</div>");
     }
@@ -1819,7 +1810,8 @@ fn small_url_encode(s: String) -> String {
 }
 
 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
-    if let Some(v) = cx.cache.impls.get(&it.def_id) {
+    let did = it.def_id.expect_real();
+    if let Some(v) = cx.cache.impls.get(&did) {
         let mut used_links = FxHashSet::default();
         let cache = cx.cache();
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 1bf726dd31a..70b5458ece8 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -270,14 +270,18 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                         w,
                         "<tr><td><code>{}extern crate {} as {};",
                         myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(myitem.def_id, &*src.as_str(), cx),
+                        anchor(myitem.def_id.expect_real(), &*src.as_str(), cx),
                         myitem.name.as_ref().unwrap(),
                     ),
                     None => write!(
                         w,
                         "<tr><td><code>{}extern crate {};",
                         myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(myitem.def_id, &*myitem.name.as_ref().unwrap().as_str(), cx),
+                        anchor(
+                            myitem.def_id.expect_real(),
+                            &*myitem.name.as_ref().unwrap().as_str(),
+                            cx
+                        ),
                     ),
                 }
                 w.write_str("</code></td></tr>");
@@ -290,7 +294,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
 
                     // Just need an item with the correct def_id and attrs
                     let import_item = clean::Item {
-                        def_id: import_def_id,
+                        def_id: import_def_id.into(),
                         attrs: import_attrs,
                         cfg: ast_attrs.cfg(cx.tcx().sess.diagnostic()),
                         ..myitem.clone()
@@ -629,7 +633,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
     }
 
     // If there are methods directly on this trait object, render them here.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All);
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All);
 
     if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
         // The DefId is for the first Type found with that name. The bool is
@@ -752,7 +756,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         path = if it.def_id.is_local() {
             cx.current.join("/")
         } else {
-            let (ref path, _) = cx.cache.external_paths[&it.def_id];
+            let (ref path, _) = cx.cache.external_paths[&it.def_id.expect_real()];
             path[..path.len() - 1].join("/")
         },
         ty = it.type_(),
@@ -778,7 +782,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
@@ -799,7 +803,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
@@ -820,7 +824,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
@@ -866,7 +870,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             document(w, cx, field, Some(it));
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
@@ -1000,7 +1004,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             render_stability_since(w, variant, it, cx.tcx());
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
@@ -1049,7 +1053,7 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean
 
 fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
     document(w, cx, it, None);
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
@@ -1137,7 +1141,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
             }
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
@@ -1166,7 +1170,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
 
     document(w, cx, it, None);
 
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 8e10c696df0..c493801d990 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -464,6 +464,8 @@ pub(super) fn write_shared(
     // Update the list of all implementors for traits
     let dst = cx.dst.join("implementors");
     for (&did, imps) in &cx.cache.implementors {
+        let did = did.expect_real();
+
         // Private modules can leak through to this phase of rustdoc, which
         // could contain implementations for otherwise private types. In some
         // rare cases we could find an implementation for an item which wasn't
@@ -496,7 +498,7 @@ pub(super) fn write_shared(
                 //
                 // If the implementation is from another crate then that crate
                 // should add it.
-                if imp.impl_item.def_id.krate == did.krate || !imp.impl_item.def_id.is_local() {
+                if imp.impl_item.def_id.krate() == did.krate || !imp.impl_item.def_id.is_local() {
                     None
                 } else {
                     Some(Implementor {
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 3d4d8df0a71..14e2d65d94e 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -177,7 +177,7 @@ fn print_src(buf: &mut Buffer, s: &str, edition: Edition) {
     }
     buf.write_str("<pre class=\"line-numbers\">");
     for i in 1..=lines {
-        write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols);
+        writeln!(buf, "<span id=\"{0}\">{0:1$}</span>", i, cols);
     }
     buf.write_str("</pre>");
     highlight::render_with_highlighting(s, buf, None, None, None, edition);
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index e81eaca8f0e..1bc53625924 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -1156,8 +1156,6 @@ function hideThemeButtonState() {
         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
         var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
-        var hideTraitImplementations =
-            getSettingValue("auto-hide-trait-implementations") !== "false";
 
         var impl_list = document.getElementById("trait-implementations-list");
         if (impl_list !== null) {
@@ -1173,39 +1171,18 @@ function hideThemeButtonState() {
             });
         }
 
-        var func = function(e) {
-            var next = e.nextElementSibling;
-            if (next && hasClass(next, "item-info")) {
-              next = next.nextElementSibling;
-            }
-            if (!next) {
-                return;
-            }
-            if (hasClass(next, "docblock")) {
-                var newToggle = toggle.cloneNode(true);
-                insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
-                if (hideMethodDocs === true && hasClass(e, "method") === true) {
-                    collapseDocs(newToggle, "hide");
+        if (hideMethodDocs === true) {
+            onEachLazy(document.getElementsByClassName("method"), function(e) {
+                var toggle = e.parentNode;
+                if (toggle) {
+                    toggle = toggle.parentNode;
                 }
-            }
-        };
-
-        var funcImpl = function(e) {
-            var next = e.nextElementSibling;
-            if (next && hasClass(next, "item-info")) {
-                next = next.nextElementSibling;
-            }
-            if (next && hasClass(next, "docblock")) {
-                next = next.nextElementSibling;
-            }
-            if (!next) {
-                return;
-            }
-        };
+                if (toggle && toggle.tagName === "DETAILS") {
+                    toggle.open = false;
+                }
+            });
+        }
 
-        onEachLazy(document.getElementsByClassName("method"), func);
-        onEachLazy(document.getElementsByClassName("associatedconstant"), func);
-        var impl_call = function() {};
         onEachLazy(document.getElementsByTagName("details"), function (e) {
             var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle");
             var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle");
@@ -1213,60 +1190,6 @@ function hideThemeButtonState() {
                 e.open = true;
             }
         });
-        if (hideMethodDocs === true) {
-            impl_call = function(e, newToggle) {
-                if (e.id.match(/^impl(?:-\d+)?$/) === null) {
-                    // Automatically minimize all non-inherent impls
-                    if (hasClass(e, "impl") === true) {
-                        collapseDocs(newToggle, "hide");
-                    }
-                }
-            };
-        }
-        var newToggle = document.createElement("a");
-        newToggle.href = "javascript:void(0)";
-        newToggle.className = "collapse-toggle hidden-default collapsed";
-        newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
-                              "</span>] Show hidden undocumented items";
-        function toggleClicked() {
-            if (hasClass(this, "collapsed")) {
-                removeClass(this, "collapsed");
-                onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
-                    if (hasClass(x, "content") === false) {
-                        removeClass(x, "hidden");
-                        addClass(x, "x");
-                    }
-                }, true);
-                this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
-                                 "</span>] Hide undocumented items";
-            } else {
-                addClass(this, "collapsed");
-                onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
-                    if (hasClass(x, "content") === false) {
-                        addClass(x, "hidden");
-                        removeClass(x, "x");
-                    }
-                }, true);
-                this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
-                                 "</span>] Show hidden undocumented items";
-            }
-        }
-        onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
-            onEachLazy(e.getElementsByClassName("associatedconstant"), func);
-            // We transform the DOM iterator into a vec of DOM elements to prevent performance
-            // issues on webkit browsers.
-            var hiddenElems = Array.prototype.slice.call(e.getElementsByClassName("hidden"));
-            var needToggle = hiddenElems.some(function(hiddenElem) {
-                return hasClass(hiddenElem, "content") === false &&
-                    hasClass(hiddenElem, "docblock") === false;
-            });
-            if (needToggle === true) {
-                var inner_toggle = newToggle.cloneNode(true);
-                inner_toggle.onclick = toggleClicked;
-                e.insertBefore(inner_toggle, e.firstChild);
-                impl_call(e.previousSibling, inner_toggle);
-            }
-        });
 
         var currentType = document.getElementsByClassName("type-decl")[0];
         var className = null;
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index a95c90e999f..d3fe59e8d0b 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -110,7 +110,7 @@ h3 {
 	font-size: 1.3em;
 }
 h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
 	font-weight: 500;
 	margin: 20px 0 15px 0;
 	padding-bottom: 6px;
@@ -128,10 +128,10 @@ h1.fqn > .in-band > a:hover {
 	text-decoration: underline;
 }
 h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
 	border-bottom: 1px solid;
 }
-h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
+h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype {
 	flex-basis: 100%;
 	font-weight: 600;
 	margin-top: 16px;
@@ -139,7 +139,7 @@ h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
 	position: relative;
 }
 h3.impl, h3.method, h4.method.trait-impl, h3.type,
-h4.type.trait-impl, h4.associatedconstant.trait-impl {
+h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl {
 	padding-left: 15px;
 }
 
@@ -147,6 +147,9 @@ h1, h2, h3, h4,
 .sidebar, a.source, .search-input, .content table td:first-child > a,
 .collapse-toggle, div.item-list .out-of-band,
 #source-sidebar, #sidebar-toggle,
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before,
+.content ul.crate a.crate,
 /* This selector is for the items listed in the "all items" page. */
 #main > ul.docblock > li > a {
 	font-family: "Fira Sans", Arial, sans-serif;
@@ -154,7 +157,6 @@ h1, h2, h3, h4,
 
 .content ul.crate a.crate {
 	font-size: 16px/1.6;
-	font-family: "Fira Sans", Arial, sans-serif;
 }
 
 ol, ul {
@@ -596,7 +598,10 @@ h4 > code, h3 > code, .invisible > code {
 	left: -19px;
 }
 
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
+.impl-items > .associatedtype, .content .impl-items details > summary > .type,
+.impl-items details > summary > .associatedconstant,
+.impl-items details > summary > .associatedtype {
 	margin-left: 20px;
 }
 
@@ -656,7 +661,8 @@ a {
 }
 
 .in-band:hover > .anchor, .impl:hover > .anchor, .method.trait-impl:hover > .anchor,
-.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor {
+.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor,
+.associatedtype.trait-impl:hover > .anchor {
 	display: inline-block;
 	position: absolute;
 }
@@ -1466,7 +1472,8 @@ h4 > .notable-traits {
 		margin-left: 0;
 	}
 
-	.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+	.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
+	.impl-items > .associatedtype {
 		display: flex;
 	}
 
@@ -1764,7 +1771,10 @@ details.rustdoc-toggle > summary.hideme {
 	cursor: pointer;
 }
 
-details.rustdoc-toggle > summary::-webkit-details-marker {
+details.rustdoc-toggle > summary::-webkit-details-marker,
+details.rustdoc-toggle > summary::marker,
+details.undocumented > summary::-webkit-details-marker,
+details.undocumented > summary::marker {
 	display: none;
 }
 
@@ -1787,6 +1797,14 @@ details.rustdoc-toggle > summary.hideme::before {
 details.rustdoc-toggle > summary:not(.hideme)::before {
 	position: absolute;
 	left: -23px;
+	top: initial;
+}
+
+.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
+.undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
+	position: absolute;
+	top: 3px;
+	left: -2px;
 }
 
 /* When a "hideme" summary is open and the "Expand description" or "Show
@@ -1798,7 +1816,7 @@ details.rustdoc-toggle[open] > summary.hideme {
 	position: absolute;
 }
 
-details.rustdoc-toggle[open] {
+details.rustdoc-toggle, details.undocumented {
 	position: relative;
 }
 
@@ -1810,3 +1828,14 @@ details.rustdoc-toggle[open] > summary::before {
 	content: "[−]";
 	display: inline;
 }
+
+details.undocumented > summary::before {
+	content: "[+] Show hidden undocumented items";
+	cursor: pointer;
+	font-size: 16px;
+	font-weight: 300;
+}
+
+details.undocumented[open] > summary::before {
+	content: "[-] Hide undocumented items";
+}
diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css
index 72396ec6b76..aace0b3c037 100644
--- a/src/librustdoc/html/static/themes/ayu.css
+++ b/src/librustdoc/html/static/themes/ayu.css
@@ -226,7 +226,8 @@ a {
 
 .collapse-toggle,
 details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
 	color: #999;
 }
 
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index b2003b52741..c23e95ce107 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -188,7 +188,8 @@ a.test-arrow {
 
 .collapse-toggle,
 details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
 	color: #999;
 }
 
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index 04187773b64..93309721210 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -186,7 +186,8 @@ a.test-arrow {
 
 .collapse-toggle,
 details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
 	color: #999;
 }
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 8ca6342462f..e3f1c6b1e2d 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -9,13 +9,14 @@ use std::convert::From;
 use rustc_ast::ast;
 use rustc_hir::def::CtorKind;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_span::Pos;
 
 use rustdoc_json_types::*;
 
 use crate::clean;
 use crate::clean::utils::print_const_expr;
+use crate::clean::FakeDefId;
 use crate::formats::item_type::ItemType;
 use crate::json::JsonRenderer;
 use std::collections::HashSet;
@@ -48,7 +49,7 @@ impl JsonRenderer<'_> {
         };
         Some(Item {
             id: from_def_id(def_id),
-            crate_id: def_id.krate.as_u32(),
+            crate_id: def_id.krate().as_u32(),
             name: name.map(|sym| sym.to_string()),
             span: self.convert_span(span),
             visibility: self.convert_visibility(visibility),
@@ -87,7 +88,7 @@ impl JsonRenderer<'_> {
             Inherited => Visibility::Default,
             Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
             Restricted(did) => Visibility::Restricted {
-                parent: from_def_id(did),
+                parent: from_def_id(did.into()),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
             },
         }
@@ -171,8 +172,13 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
     }
 }
 
-crate fn from_def_id(did: DefId) -> Id {
-    Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index)))
+crate fn from_def_id(did: FakeDefId) -> Id {
+    match did {
+        FakeDefId::Real(did) => Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index))),
+        // We need to differentiate real and fake ids, because the indices might overlap for fake
+        // and real DefId's, which would cause two different Id's treated as they were the same.
+        FakeDefId::Fake(idx, krate) => Id(format!("F{}:{}", krate.as_u32(), u32::from(idx))),
+    }
 }
 
 fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
@@ -368,7 +374,7 @@ impl FromWithTcx<clean::Type> for Type {
         match ty {
             ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath {
                 name: path.whole_name(),
-                id: from_def_id(did),
+                id: from_def_id(did.into()),
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
                 param_names: param_names
                     .map(|v| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
@@ -540,13 +546,13 @@ impl FromWithTcx<clean::Import> for Import {
             Simple(s) => Import {
                 source: import.source.path.whole_name(),
                 name: s.to_string(),
-                id: import.source.did.map(from_def_id),
+                id: import.source.did.map(FakeDefId::from).map(from_def_id),
                 glob: false,
             },
             Glob => Import {
                 source: import.source.path.whole_name(),
                 name: import.source.path.last_name().to_string(),
-                id: import.source.did.map(from_def_id),
+                id: import.source.did.map(FakeDefId::from).map(from_def_id),
                 glob: true,
             },
         }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index ae4d1be3ec2..d56acad60c0 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -17,7 +17,8 @@ use rustc_session::Session;
 
 use rustdoc_json_types as types;
 
-use crate::clean::{self, ExternalCrate};
+use crate::clean;
+use crate::clean::{ExternalCrate, FakeDefId};
 use crate::config::RenderOptions;
 use crate::error::Error;
 use crate::formats::cache::Cache;
@@ -41,7 +42,7 @@ impl JsonRenderer<'tcx> {
         self.tcx.sess
     }
 
-    fn get_trait_implementors(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+    fn get_trait_implementors(&mut self, id: FakeDefId) -> Vec<types::Id> {
         Rc::clone(&self.cache)
             .implementors
             .get(&id)
@@ -58,10 +59,10 @@ impl JsonRenderer<'tcx> {
             .unwrap_or_default()
     }
 
-    fn get_impls(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+    fn get_impls(&mut self, id: FakeDefId) -> Vec<types::Id> {
         Rc::clone(&self.cache)
             .impls
-            .get(&id)
+            .get(&id.expect_real())
             .map(|impls| {
                 impls
                     .iter()
@@ -89,9 +90,9 @@ impl JsonRenderer<'tcx> {
                     let trait_item = &trait_item.trait_;
                     trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
                     Some((
-                        from_def_id(id),
+                        from_def_id(id.into()),
                         types::Item {
-                            id: from_def_id(id),
+                            id: from_def_id(id.into()),
                             crate_id: id.krate.as_u32(),
                             name: self
                                 .cache
@@ -205,7 +206,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .chain(self.cache.external_paths.clone().into_iter())
                 .map(|(k, (path, kind))| {
                     (
-                        from_def_id(k),
+                        from_def_id(k.into()),
                         types::ItemSummary {
                             crate_id: k.krate.as_u32(),
                             path,
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 985aeedabb1..169ef015fa8 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -82,8 +82,6 @@ use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGro
 use rustc_session::getopts;
 use rustc_session::{early_error, early_warn};
 
-use crate::clean::utils::doc_rust_lang_org_channel;
-
 /// A macro to create a FxHashMap.
 ///
 /// Example:
@@ -595,6 +593,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")),
     ]
 }
 
@@ -605,10 +604,7 @@ fn usage(argv0: &str) {
     }
     println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
     println!("    @path               Read newline separated options from `path`\n");
-    println!(
-        "More information available at https://doc.rust-lang.org/{}/rustdoc/what-is-rustdoc.html",
-        doc_rust_lang_org_channel()
-    );
+    println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
 }
 
 /// A result type used by several functions under `main()`.
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 68a66806e04..8d07cde5188 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -111,7 +111,11 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if let Some(dox) = &item.attrs.collapsed_doc_value() {
             let sp = item.attr_span(self.cx.tcx);
-            let extra = crate::html::markdown::ExtraInfo::new_did(self.cx.tcx, item.def_id, sp);
+            let extra = crate::html::markdown::ExtraInfo::new_did(
+                self.cx.tcx,
+                item.def_id.expect_real(),
+                sp,
+            );
             for code_block in markdown::rust_code_blocks(&dox, &extra) {
                 self.check_rust_syntax(&item, &dox, code_block);
             }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index f1064756fdd..25b6c187f3b 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -30,7 +30,9 @@ use std::convert::{TryFrom, TryInto};
 use std::mem;
 use std::ops::Range;
 
-use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
+use crate::clean::{
+    self, utils::find_nearest_parent_module, Crate, FakeDefId, Item, ItemLink, PrimitiveType,
+};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::{markdown_links, MarkdownLink};
@@ -246,7 +248,7 @@ enum AnchorFailure {
 
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 struct ResolutionInfo {
-    module_id: DefId,
+    module_id: FakeDefId,
     dis: Option<Disambiguator>,
     path_str: String,
     extra_fragment: Option<String>,
@@ -272,7 +274,7 @@ struct LinkCollector<'a, 'tcx> {
     ///
     /// The last module will be used if the parent scope of the current item is
     /// unknown.
-    mod_ids: Vec<DefId>,
+    mod_ids: Vec<FakeDefId>,
     /// This is used to store the kind of associated items,
     /// because `clean` and the disambiguator code expect them to be different.
     /// See the code for associated items on inherent impls for details.
@@ -296,7 +298,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
-            module_id,
+            module_id: module_id.into(),
             partial_res: None,
             unresolved: path_str.into(),
         };
@@ -524,7 +526,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     // but the disambiguator logic expects the associated item.
                     // Store the kind in a side channel so that only the disambiguator logic looks at it.
                     if let Some((kind, id)) = side_channel {
-                        self.kind_side_channel.set(Some((kind, id)));
+                        self.kind_side_channel.set(Some((kind, id.into())));
                     }
                     Ok((res, Some(fragment)))
                 };
@@ -795,7 +797,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         let parent_node = if item.is_fake() {
             None
         } else {
-            find_nearest_parent_module(self.cx.tcx, item.def_id)
+            find_nearest_parent_module(self.cx.tcx, item.def_id.expect_real())
         };
 
         if parent_node.is_some() {
@@ -807,31 +809,34 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         let self_id = if item.is_fake() {
             None
         // Checking if the item is a field in an enum variant
-        } else if (matches!(self.cx.tcx.def_kind(item.def_id), DefKind::Field)
+        } else if (matches!(self.cx.tcx.def_kind(item.def_id.expect_real()), DefKind::Field)
             && matches!(
-                self.cx.tcx.def_kind(self.cx.tcx.parent(item.def_id).unwrap()),
+                self.cx.tcx.def_kind(self.cx.tcx.parent(item.def_id.expect_real()).unwrap()),
                 DefKind::Variant
             ))
         {
-            self.cx.tcx.parent(item.def_id).and_then(|item_id| self.cx.tcx.parent(item_id))
+            self.cx
+                .tcx
+                .parent(item.def_id.expect_real())
+                .and_then(|item_id| self.cx.tcx.parent(item_id))
         } else if matches!(
-            self.cx.tcx.def_kind(item.def_id),
+            self.cx.tcx.def_kind(item.def_id.expect_real()),
             DefKind::AssocConst
                 | DefKind::AssocFn
                 | DefKind::AssocTy
                 | DefKind::Variant
                 | DefKind::Field
         ) {
-            self.cx.tcx.parent(item.def_id)
+            self.cx.tcx.parent(item.def_id.expect_real())
         // HACK(jynelson): `clean` marks associated types as `TypedefItem`, not as `AssocTypeItem`.
         // Fixing this breaks `fn render_deref_methods`.
         // As a workaround, see if the parent of the item is an `impl`; if so this must be an associated item,
         // regardless of what rustdoc wants to call it.
-        } else if let Some(parent) = self.cx.tcx.parent(item.def_id) {
+        } else if let Some(parent) = self.cx.tcx.parent(item.def_id.expect_real()) {
             let parent_kind = self.cx.tcx.def_kind(parent);
-            Some(if parent_kind == DefKind::Impl { parent } else { item.def_id })
+            Some(if parent_kind == DefKind::Impl { parent } else { item.def_id.expect_real() })
         } else {
-            Some(item.def_id)
+            Some(item.def_id.expect_real())
         };
 
         // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
@@ -869,7 +874,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             let (krate, parent_node) = if let Some(id) = parent_module {
                 (id.krate, Some(id))
             } else {
-                (item.def_id.krate, parent_node)
+                (item.def_id.krate(), parent_node)
             };
             // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
             // This is a degenerate case and it's not supported by rustdoc.
@@ -1065,8 +1070,11 @@ impl LinkCollector<'_, '_> {
         // we've already pushed this node onto the resolution stack but
         // for outer comments we explicitly try and resolve against the
         // parent_node first.
-        let base_node =
-            if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node };
+        let base_node = if item.is_mod() && inner_docs {
+            self.mod_ids.last().copied()
+        } else {
+            parent_node.map(|id| FakeDefId::new_real(id))
+        };
 
         let mut module_id = if let Some(id) = base_node {
             id
@@ -1111,7 +1119,7 @@ impl LinkCollector<'_, '_> {
                 resolved_self = format!("self::{}", &path_str["crate::".len()..]);
                 path_str = &resolved_self;
             }
-            module_id = DefId { krate, index: CRATE_DEF_INDEX };
+            module_id = FakeDefId::new_real(DefId { krate, index: CRATE_DEF_INDEX });
         }
 
         let (mut res, mut fragment) = self.resolve_with_disambiguator_cached(
@@ -1172,8 +1180,8 @@ impl LinkCollector<'_, '_> {
             report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
         };
 
-        let verify = |kind: DefKind, id: DefId| {
-            let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id));
+        let verify = |kind: DefKind, id: FakeDefId| {
+            let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id.expect_real()));
             debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
 
             // Disallow e.g. linking to enums with `struct@`
@@ -1227,7 +1235,7 @@ impl LinkCollector<'_, '_> {
                     // doesn't allow statements like `use str::trim;`, making this a (hopefully)
                     // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
                     // for discussion on the matter.
-                    verify(kind, id)?;
+                    verify(kind, id.into())?;
 
                     // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
                     // However I'm not sure how to check that across crates.
@@ -1265,9 +1273,9 @@ impl LinkCollector<'_, '_> {
                 Some(ItemLink { link: ori_link.link, link_text, did: None, fragment })
             }
             Res::Def(kind, id) => {
-                verify(kind, id)?;
+                verify(kind, id.into())?;
                 let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
-                Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment })
+                Some(ItemLink { link: ori_link.link, link_text, did: Some(id.into()), fragment })
             }
         }
     }
@@ -1333,7 +1341,7 @@ impl LinkCollector<'_, '_> {
 
         match disambiguator.map(Disambiguator::ns) {
             Some(expected_ns @ (ValueNS | TypeNS)) => {
-                match self.resolve(path_str, expected_ns, base_node, extra_fragment) {
+                match self.resolve(path_str, expected_ns, base_node.expect_real(), extra_fragment) {
                     Ok(res) => Some(res),
                     Err(ErrorKind::Resolve(box mut kind)) => {
                         // We only looked in one namespace. Try to give a better error if possible.
@@ -1342,9 +1350,12 @@ impl LinkCollector<'_, '_> {
                             // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
                             // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
                             for &new_ns in &[other_ns, MacroNS] {
-                                if let Some(res) =
-                                    self.check_full_res(new_ns, path_str, base_node, extra_fragment)
-                                {
+                                if let Some(res) = self.check_full_res(
+                                    new_ns,
+                                    path_str,
+                                    base_node.expect_real(),
+                                    extra_fragment,
+                                ) {
                                     kind = ResolutionFailure::WrongNamespace { res, expected_ns };
                                     break;
                                 }
@@ -1366,9 +1377,14 @@ impl LinkCollector<'_, '_> {
                 // Try everything!
                 let mut candidates = PerNS {
                     macro_ns: self
-                        .resolve_macro(path_str, base_node)
+                        .resolve_macro(path_str, base_node.expect_real())
                         .map(|res| (res, extra_fragment.clone())),
-                    type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
+                    type_ns: match self.resolve(
+                        path_str,
+                        TypeNS,
+                        base_node.expect_real(),
+                        extra_fragment,
+                    ) {
                         Ok(res) => {
                             debug!("got res in TypeNS: {:?}", res);
                             Ok(res)
@@ -1379,7 +1395,12 @@ impl LinkCollector<'_, '_> {
                         }
                         Err(ErrorKind::Resolve(box kind)) => Err(kind),
                     },
-                    value_ns: match self.resolve(path_str, ValueNS, base_node, extra_fragment) {
+                    value_ns: match self.resolve(
+                        path_str,
+                        ValueNS,
+                        base_node.expect_real(),
+                        extra_fragment,
+                    ) {
                         Ok(res) => Ok(res),
                         Err(ErrorKind::AnchorFailure(msg)) => {
                             anchor_failure(self.cx, diag, msg);
@@ -1421,7 +1442,7 @@ impl LinkCollector<'_, '_> {
                 }
 
                 if len == 1 {
-                    Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap())
+                    Some(candidates.into_iter().find_map(|res| res.ok()).unwrap())
                 } else if len == 2 && is_derive_trait_collision(&candidates) {
                     Some(candidates.type_ns.unwrap())
                 } else {
@@ -1435,14 +1456,17 @@ impl LinkCollector<'_, '_> {
                 }
             }
             Some(MacroNS) => {
-                match self.resolve_macro(path_str, base_node) {
+                match self.resolve_macro(path_str, base_node.expect_real()) {
                     Ok(res) => Some((res, extra_fragment.clone())),
                     Err(mut kind) => {
                         // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
                         for &ns in &[TypeNS, ValueNS] {
-                            if let Some(res) =
-                                self.check_full_res(ns, path_str, base_node, extra_fragment)
-                            {
+                            if let Some(res) = self.check_full_res(
+                                ns,
+                                path_str,
+                                base_node.expect_real(),
+                                extra_fragment,
+                            ) {
                                 kind =
                                     ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS };
                                 break;
@@ -1795,7 +1819,7 @@ fn resolution_failure(
                         name = start;
                         for &ns in &[TypeNS, ValueNS, MacroNS] {
                             if let Some(res) =
-                                collector.check_full_res(ns, &start, module_id, &None)
+                                collector.check_full_res(ns, &start, module_id.into(), &None)
                             {
                                 debug!("found partial_res={:?}", res);
                                 *partial_res = Some(res);
@@ -1993,14 +2017,7 @@ fn disambiguator_error(
     msg: &str,
 ) {
     diag_info.link_range = disambiguator_range;
-    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
-        let msg = format!(
-            "see https://doc.rust-lang.org/{}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators \
-             for more info about disambiguators",
-            crate::doc_rust_lang_org_channel(),
-        );
-        diag.note(&msg);
-    });
+    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |_diag, _sp| {});
 }
 
 /// Report an ambiguity error, where there were multiple possible resolutions.
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 7b0b2f28fdf..90b797da249 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -46,7 +46,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
 
                 // FIXME(eddyb) is this `doc(hidden)` check needed?
                 if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
-                    let impls = get_auto_trait_and_blanket_impls(cx, def_id);
+                    let impls = get_auto_trait_and_blanket_impls(cx, def_id.into());
                     new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
                 }
             });
@@ -117,8 +117,8 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
                     // Avoid infinite cycles
                     return;
                 }
-                cleaner.items.insert(target_did);
-                add_deref_target(map, cleaner, &target_did);
+                cleaner.items.insert(target_did.into());
+                add_deref_target(map, cleaner, &target_did.into());
             }
         }
     }
@@ -126,7 +126,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
         // Since only the `DefId` portion of the `Type` instances is known to be same for both the
         // `Deref` target type and the impl for type positions, this map of types is keyed by
         // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
-        if cleaner.keep_impl_with_def_id(type_did) {
+        if cleaner.keep_impl_with_def_id(&FakeDefId::new_real(*type_did)) {
             add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
         }
     }
@@ -163,8 +163,10 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
-            if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
-                self.impls.extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id));
+            if !self.cx.tcx.get_attrs(i.def_id.expect_real()).lists(sym::doc).has_word(sym::hidden)
+            {
+                self.impls
+                    .extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id.expect_real()));
             }
         }
 
@@ -174,7 +176,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
 
 #[derive(Default)]
 struct ItemCollector {
-    items: FxHashSet<DefId>,
+    items: FxHashSet<FakeDefId>,
 }
 
 impl ItemCollector {
@@ -193,7 +195,7 @@ impl DocFolder for ItemCollector {
 
 struct BadImplStripper {
     prims: FxHashSet<PrimitiveType>,
-    items: FxHashSet<DefId>,
+    items: FxHashSet<FakeDefId>,
 }
 
 impl BadImplStripper {
@@ -204,13 +206,13 @@ impl BadImplStripper {
         } else if let Some(prim) = ty.primitive_type() {
             self.prims.contains(&prim)
         } else if let Some(did) = ty.def_id() {
-            self.keep_impl_with_def_id(&did)
+            self.keep_impl_with_def_id(&did.into())
         } else {
             false
         }
     }
 
-    fn keep_impl_with_def_id(&self, did: &DefId) -> bool {
+    fn keep_impl_with_def_id(&self, did: &FakeDefId) -> bool {
         self.items.contains(did)
     }
 }
diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs
index c8d2263d81d..7362cfcb71b 100644
--- a/src/librustdoc/passes/doc_test_lints.rs
+++ b/src/librustdoc/passes/doc_test_lints.rs
@@ -53,7 +53,7 @@ impl crate::doctest::Tester for Tests {
 }
 
 crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
-    if !cx.cache.access_levels.is_public(item.def_id)
+    if !cx.cache.access_levels.is_public(item.def_id.expect_real())
         || matches!(
             *item.kind,
             clean::StructFieldItem(_)
@@ -105,7 +105,8 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
                 |lint| lint.build("missing code example in this documentation").emit(),
             );
         }
-    } else if tests.found_tests > 0 && !cx.cache.access_levels.is_public(item.def_id) {
+    } else if tests.found_tests > 0 && !cx.cache.access_levels.is_public(item.def_id.expect_real())
+    {
         cx.tcx.struct_span_lint_hir(
             crate::lint::PRIVATE_DOC_TESTS,
             hir_id,
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 54c4ed22f1c..e5910d081a5 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -1,9 +1,8 @@
-use rustc_hir::def_id::DefIdSet;
 use rustc_span::symbol::sym;
 use std::mem;
 
 use crate::clean;
-use crate::clean::{Item, NestedAttributesExt};
+use crate::clean::{FakeDefIdSet, Item, NestedAttributesExt};
 use crate::core::DocContext;
 use crate::fold::{DocFolder, StripItem};
 use crate::passes::{ImplStripper, Pass};
@@ -16,7 +15,7 @@ crate const STRIP_HIDDEN: Pass = Pass {
 
 /// Strip items marked `#[doc(hidden)]`
 crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
-    let mut retained = DefIdSet::default();
+    let mut retained = FakeDefIdSet::default();
 
     // strip all #[doc(hidden)] items
     let krate = {
@@ -30,7 +29,7 @@ crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Cra
 }
 
 struct Stripper<'a> {
-    retained: &'a mut DefIdSet,
+    retained: &'a mut FakeDefIdSet,
     update_retained: bool,
 }
 
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index fc8bbc97150..18abeb607a1 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -1,6 +1,4 @@
-use rustc_hir::def_id::DefIdSet;
-
-use crate::clean;
+use crate::clean::{self, FakeDefIdSet};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
@@ -16,7 +14,7 @@ crate const STRIP_PRIVATE: Pass = Pass {
 /// crate, specified by the `xcrate` flag.
 crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     // This stripper collects all *retained* nodes.
-    let mut retained = DefIdSet::default();
+    let mut retained = FakeDefIdSet::default();
 
     // strip all private items
     {
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 44d54563f27..87399256292 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -1,12 +1,12 @@
-use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_hir::def_id::DefId;
 use rustc_middle::middle::privacy::AccessLevels;
 use std::mem;
 
-use crate::clean::{self, GetDefId, Item};
+use crate::clean::{self, FakeDefIdSet, GetDefId, Item};
 use crate::fold::{DocFolder, StripItem};
 
 crate struct Stripper<'a> {
-    crate retained: &'a mut DefIdSet,
+    crate retained: &'a mut FakeDefIdSet,
     crate access_levels: &'a AccessLevels<DefId>,
     crate update_retained: bool,
 }
@@ -42,7 +42,7 @@ impl<'a> DocFolder for Stripper<'a> {
             | clean::TraitAliasItem(..)
             | clean::ForeignTypeItem => {
                 if i.def_id.is_local() {
-                    if !self.access_levels.is_exported(i.def_id) {
+                    if !self.access_levels.is_exported(i.def_id.expect_real()) {
                         debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
                         return None;
                     }
@@ -116,7 +116,7 @@ impl<'a> DocFolder for Stripper<'a> {
 
 /// This stripper discards all impls which reference stripped items
 crate struct ImplStripper<'a> {
-    crate retained: &'a DefIdSet,
+    crate retained: &'a FakeDefIdSet,
 }
 
 impl<'a> DocFolder for ImplStripper<'a> {
@@ -127,13 +127,14 @@ impl<'a> DocFolder for ImplStripper<'a> {
                 return None;
             }
             if let Some(did) = imp.for_.def_id() {
-                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
+                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into())
+                {
                     debug!("ImplStripper: impl item for stripped type; removing");
                     return None;
                 }
             }
             if let Some(did) = imp.trait_.def_id() {
-                if did.is_local() && !self.retained.contains(&did) {
+                if did.is_local() && !self.retained.contains(&did.into()) {
                     debug!("ImplStripper: impl item for stripped trait; removing");
                     return None;
                 }
@@ -141,7 +142,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
                 for typaram in generics {
                     if let Some(did) = typaram.def_id() {
-                        if did.is_local() && !self.retained.contains(&did) {
+                        if did.is_local() && !self.retained.contains(&did.into()) {
                             debug!(
                                 "ImplStripper: stripped item in trait's generics; removing impl"
                             );
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 24d57705412..b8b3f9634e5 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -17,7 +17,7 @@ crate struct CssPath {
 // This PartialEq implementation IS NOT COMMUTATIVE!!!
 //
 // The order is very important: the second object must have all first's rules.
-// However, the first doesn't require to have all second's rules.
+// However, the first is not required to have all of the second's rules.
 impl PartialEq for CssPath {
     fn eq(&self, other: &CssPath) -> bool {
         if self.name != other.name {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index c9071eea78b..191d8d5a2ea 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -8,9 +8,9 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::Node;
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
+use rustc_span;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{self, Span};
 
 use std::mem;
 
@@ -73,7 +73,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
         let span = krate.item.inner;
         let mut top_level_module = self.visit_mod_contents(
-            span,
             &Spanned { span, node: hir::VisibilityKind::Public },
             hir::CRATE_HIR_ID,
             &krate.item,
@@ -129,16 +128,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
     fn visit_mod_contents(
         &mut self,
-        span: Span,
         vis: &hir::Visibility<'_>,
         id: hir::HirId,
         m: &'tcx hir::Mod<'tcx>,
         name: Symbol,
     ) -> Module<'tcx> {
-        let mut om = Module::new(name);
-        om.where_outer = span;
-        om.where_inner = m.inner;
-        om.id = id;
+        let mut om = Module::new(name, id, m.inner);
         // Keep track of if there were any private modules in the path.
         let orig_inside_public_path = self.inside_public_path;
         self.inside_public_path &= vis.node.is_pub();
@@ -196,7 +191,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     } else {
                         // All items need to be handled here in case someone wishes to link
                         // to them with intra-doc links
-                        self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
+                        self.cx.cache.access_levels.map.insert(did.into(), AccessLevel::Public);
                     }
                 }
             }
@@ -208,7 +203,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             None => return false,
         };
 
-        let is_private = !self.cx.cache.access_levels.is_public(res_did);
+        let is_private = !self.cx.cache.access_levels.is_public(res_did.into());
         let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
 
         // Only inline if requested or if the item would otherwise be stripped.
@@ -312,7 +307,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.items.push((item, renamed))
             }
             hir::ItemKind::Mod(ref m) => {
-                om.mods.push(self.visit_mod_contents(item.span, &item.vis, item.hir_id(), m, name));
+                om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
             }
             hir::ItemKind::Fn(..)
             | hir::ItemKind::ExternCrate(..)
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/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/should-fail.rs b/src/test/debuginfo/should-fail.rs
index 1e0d22cbce4..eef6d99d2a9 100644
--- a/src/test/debuginfo/should-fail.rs
+++ b/src/test/debuginfo/should-fail.rs
@@ -2,6 +2,7 @@
 
 // == Test [gdb|lldb]-[command|check] are parsed correctly ===
 // should-fail
+// needs-run-enabled
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
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/ast-stmt-expr-attr.rs b/src/test/pretty/ast-stmt-expr-attr.rs
index 5b975424512..de42a8c4ed5 100644
--- a/src/test/pretty/ast-stmt-expr-attr.rs
+++ b/src/test/pretty/ast-stmt-expr-attr.rs
@@ -5,15 +5,15 @@ fn main() { }
 #[cfg(FALSE)]
 fn syntax() {
     let _ = #[attr] box 0;
-    let _ = #[attr] [#![attr] ];
-    let _ = #[attr] [#![attr] 0];
-    let _ = #[attr] [#![attr] 0; 0];
-    let _ = #[attr] [#![attr] 0, 0, 0];
+    let _ = #[attr] [];
+    let _ = #[attr] [0];
+    let _ = #[attr] [0; 0];
+    let _ = #[attr] [0, 0, 0];
     let _ = #[attr] foo();
     let _ = #[attr] x.foo();
-    let _ = #[attr] (#![attr] );
-    let _ = #[attr] (#![attr] #[attr] 0,);
-    let _ = #[attr] (#![attr] #[attr] 0, 0);
+    let _ = #[attr] ();
+    let _ = #[attr] (#[attr] 0,);
+    let _ = #[attr] (#[attr] 0, 0);
     let _ = #[attr] 0 + #[attr] 0;
     let _ = #[attr] 0 / #[attr] 0;
     let _ = #[attr] 0 & #[attr] 0;
@@ -43,10 +43,10 @@ fn syntax() {
                     #![attr]
                 };
     let _ =
-        #[attr] match true {
-                    #![attr]
-                            #[attr]
-                            _ => false,
+        #[attr] match true
+                    {
+                     #[attr]
+                     _ => false,
                 };
     let _ = #[attr] || #[attr] foo;
     let _ = #[attr] move || #[attr] foo;
@@ -119,10 +119,10 @@ fn syntax() {
     let _ = #[attr] foo![# ! [attr]];
     let _ = #[attr] foo! { };
     let _ = #[attr] foo! { # ! [attr] };
-    let _ = #[attr] Foo{#![attr] bar: baz,};
-    let _ = #[attr] Foo{#![attr] ..foo};
-    let _ = #[attr] Foo{#![attr] bar: baz, ..foo};
-    let _ = #[attr] (#![attr] 0);
+    let _ = #[attr] Foo{bar: baz,};
+    let _ = #[attr] Foo{..foo};
+    let _ = #[attr] Foo{bar: baz, ..foo};
+    let _ = #[attr] (0);
 
     {
         #[attr]
diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs
index 619cce685d7..54a8438f1d0 100644
--- a/src/test/pretty/stmt_expr_attributes.rs
+++ b/src/test/pretty/stmt_expr_attributes.rs
@@ -41,16 +41,9 @@ fn _3() {
 fn _4() {
 
     #[rustc_dummy]
-    match () {
-        #![rustc_dummy]
-        _ => (),
-    }
+    match () { _ => (), }
 
-    let _ =
-        #[rustc_dummy] match () {
-                           #![rustc_dummy]
-                           () => (),
-                       };
+    let _ = #[rustc_dummy] match () { () => (), };
 }
 
 fn _5() {
@@ -71,14 +64,14 @@ fn _5() {
 fn _6() {
 
     #[rustc_dummy]
-    [#![rustc_dummy] 1, 2, 3];
+    [1, 2, 3];
 
-    let _ = #[rustc_dummy] [#![rustc_dummy] 1, 2, 3];
+    let _ = #[rustc_dummy] [1, 2, 3];
 
     #[rustc_dummy]
-    [#![rustc_dummy] 1; 4];
+    [1; 4];
 
-    let _ = #[rustc_dummy] [#![rustc_dummy] 1; 4];
+    let _ = #[rustc_dummy] [1; 4];
 }
 
 struct Foo {
@@ -90,24 +83,24 @@ struct Bar(());
 fn _7() {
 
     #[rustc_dummy]
-    Foo{#![rustc_dummy] data: (),};
+    Foo{data: (),};
 
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),};
+    let _ = #[rustc_dummy] Foo{data: (),};
 }
 
 fn _8() {
 
     #[rustc_dummy]
-    (#![rustc_dummy] );
+    ();
 
     #[rustc_dummy]
-    (#![rustc_dummy] 0);
+    (0);
 
     #[rustc_dummy]
-    (#![rustc_dummy] 0,);
+    (0,);
 
     #[rustc_dummy]
-    (#![rustc_dummy] 0, 1);
+    (0, 1);
 }
 
 fn _9() {
@@ -138,15 +131,15 @@ fn _10() {
 
 fn _11() {
     let _ = #[rustc_dummy] box 0;
-    let _: [(); 0] = #[rustc_dummy] [#![rustc_dummy] ];
-    let _ = #[rustc_dummy] [#![rustc_dummy] 0, 0];
-    let _ = #[rustc_dummy] [#![rustc_dummy] 0; 0];
+    let _: [(); 0] = #[rustc_dummy] [];
+    let _ = #[rustc_dummy] [0, 0];
+    let _ = #[rustc_dummy] [0; 0];
     let _ = #[rustc_dummy] foo();
     let _ = #[rustc_dummy] 1i32.clone();
-    let _ = #[rustc_dummy] (#![rustc_dummy] );
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0);
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0,);
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0, 0);
+    let _ = #[rustc_dummy] ();
+    let _ = #[rustc_dummy] (0);
+    let _ = #[rustc_dummy] (0,);
+    let _ = #[rustc_dummy] (0, 0);
     let _ = #[rustc_dummy] 0 + #[rustc_dummy] 0;
     let _ = #[rustc_dummy] !0;
     let _ = #[rustc_dummy] -0i32;
@@ -171,11 +164,7 @@ fn _11() {
         #[rustc_dummy] loop  {
                            #![rustc_dummy]
                        };
-    let _ =
-        #[rustc_dummy] match false {
-                           #![rustc_dummy]
-                           _ => (),
-                       };
+    let _ = #[rustc_dummy] match false { _ => (), };
     let _ = #[rustc_dummy] || #[rustc_dummy] ();
     let _ = #[rustc_dummy] move || #[rustc_dummy] ();
     let _ =
@@ -237,10 +226,10 @@ fn _11() {
     let _ = #[rustc_dummy] expr_mac!();
     let _ = #[rustc_dummy] expr_mac![];
     let _ = #[rustc_dummy] expr_mac! { };
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),};
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] ..s};
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (), ..s};
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0);
+    let _ = #[rustc_dummy] Foo{data: (),};
+    let _ = #[rustc_dummy] Foo{..s};
+    let _ = #[rustc_dummy] Foo{data: (), ..s};
+    let _ = #[rustc_dummy] (0);
 }
 
 fn _12() {
diff --git a/src/test/run-make-fulldeps/alloc-extern-crates/Makefile b/src/test/run-make-fulldeps/alloc-extern-crates/Makefile
deleted file mode 100644
index 63f34594453..00000000000
--- a/src/test/run-make-fulldeps/alloc-extern-crates/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
--include ../tools.mk
-
-all:
-	$(RUSTC) fakealloc.rs
-	$(RUSTC) --edition=2018 --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg feature=\"external_crate\" --extern external=$(TMPDIR)/$(shell $(RUSTC) --print file-names fakealloc.rs)
diff --git a/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs b/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs
deleted file mode 100644
index d4612c325d5..00000000000
--- a/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#![crate_type = "rlib"]
-#![no_std]
-
-#[inline]
-pub unsafe fn allocate(_size: usize, _align: usize) -> *mut u8 {
-    core::ptr::null_mut()
-}
-
-#[inline]
-pub unsafe fn deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) { }
-
-#[inline]
-pub unsafe fn reallocate(_ptr: *mut u8, _old_size: usize, _size: usize, _align: usize) -> *mut u8 {
-    core::ptr::null_mut()
-}
-
-#[inline]
-pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
-                                    _align: usize) -> usize { old_size }
-
-#[inline]
-pub fn usable_size(size: usize, _align: usize) -> usize { size }
-
-#[inline]
-pub fn stats_print() { }
diff --git a/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile b/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile
new file mode 100644
index 00000000000..c68ae40eb94
--- /dev/null
+++ b/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile
@@ -0,0 +1,4 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) --edition=2018 --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg feature=\"external_crate\" --cfg no_global_oom_handling
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
index a8c79efd723..dc06a485a8f 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
@@ -15,9 +15,9 @@
                    ^0
    15|      1|}
    16|       |
-   17|       |// FIXME(#83985): The auto-generated closure in an async function is failing to include
-   18|       |// the println!() and `let` assignment lines in the coverage code region(s), as it does in the
-   19|       |// non-async function above, unless the `println!()` is inside a covered block.
+   17|       |
+   18|       |
+   19|       |
    20|      1|async fn async_func() {
    21|      1|    println!("async_func was covered");
    22|      1|    let b = true;
@@ -27,9 +27,9 @@
                    ^0
    26|      1|}
    27|       |
-   28|       |// FIXME(#83985): As above, this async function only has the `println!()` macro call, which is not
-   29|       |// showing coverage, so the entire async closure _appears_ uncovered; but this is not exactly true.
-   30|       |// It's only certain kinds of lines and/or their context that results in missing coverage.
+   28|       |
+   29|       |
+   30|       |
    31|      1|async fn async_func_just_println() {
    32|      1|    println!("async_func_just_println was covered");
    33|      1|}
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
index a39e3a16fc6..5715e0cc269 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
@@ -37,7 +37,7 @@
    37|      0|            countdown = 10;
    38|      0|        }
    39|      0|        "alt string 2".to_owned()
-   40|      1|    };
+   40|      0|    };
    41|      1|    println!(
    42|      1|        "The string or alt: {}"
    43|      1|        ,
@@ -125,36 +125,98 @@
   125|      0|            countdown = 10;
   126|      0|        }
   127|      0|        "closure should be unused".to_owned()
-  128|      1|    };
-  129|      1|
+  128|      0|    };
+  129|       |
   130|      1|    let mut countdown = 10;
   131|      1|    let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
                                                                   ^0
-  132|      1|
-  133|      1|    // Macros can sometimes confuse the coverage results. Compare this next assignment, with an
-  134|      1|    // unused closure that invokes the `println!()` macro, with the closure assignment above, that
-  135|      1|    // does not use a macro. The closure above correctly shows `0` executions.
-  136|      1|    let _short_unused_closure = | _unused_arg: u8 | println!("not called");
-  137|      1|    // The closure assignment above is executed, with a line count of `1`, but the `println!()`
-  138|      1|    // could not have been called, and yet, there is no indication that it wasn't...
-  139|      1|
-  140|      1|    // ...but adding block braces gives the expected result, showing the block was not executed.
+  132|       |
+  133|       |
+  134|      1|    let short_used_covered_closure_macro = | used_arg: u8 | println!("called");
+  135|      1|    let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called");
+                                                                              ^0
+  136|      1|    let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called");
+                                                                        ^0
+  137|       |
+  138|       |
+  139|       |
+  140|       |
   141|      1|    let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") };
                                                                         ^0
-  142|      1|
+  142|       |
   143|      1|    let _shortish_unused_closure = | _unused_arg: u8 | {
   144|      0|        println!("not called")
-  145|      1|    };
-  146|      1|
+  145|      0|    };
+  146|       |
   147|      1|    let _as_short_unused_closure = |
   148|       |        _unused_arg: u8
-  149|      1|    | { println!("not called") };
-                    ^0
-  150|      1|
+  149|      0|    | { println!("not called") };
+  150|       |
   151|      1|    let _almost_as_short_unused_closure = |
   152|       |        _unused_arg: u8
-  153|      1|    | { println!("not called") }
-                    ^0
-  154|      1|    ;
-  155|      1|}
+  153|      0|    | { println!("not called") }
+  154|       |    ;
+  155|       |
+  156|       |
+  157|       |
+  158|       |
+  159|       |
+  160|      1|    let _short_unused_closure_line_break_no_block = | _unused_arg: u8 |
+  161|      0|println!("not called")
+  162|       |    ;
+  163|       |
+  164|      1|    let _short_unused_closure_line_break_no_block2 =
+  165|       |        | _unused_arg: u8 |
+  166|      0|            println!(
+  167|      0|                "not called"
+  168|      0|            )
+  169|       |    ;
+  170|       |
+  171|      1|    let short_used_not_covered_closure_line_break_no_block_embedded_branch =
+  172|      1|        | _unused_arg: u8 |
+  173|      0|            println!(
+  174|      0|                "not called: {}",
+  175|      0|                if is_true { "check" } else { "me" }
+  176|      0|            )
+  177|       |    ;
+  178|       |
+  179|      1|    let short_used_not_covered_closure_line_break_block_embedded_branch =
+  180|      1|        | _unused_arg: u8 |
+  181|      0|        {
+  182|      0|            println!(
+  183|      0|                "not called: {}",
+  184|      0|                if is_true { "check" } else { "me" }
+  185|       |            )
+  186|      0|        }
+  187|       |    ;
+  188|       |
+  189|      1|    let short_used_covered_closure_line_break_no_block_embedded_branch =
+  190|      1|        | _unused_arg: u8 |
+  191|      1|            println!(
+  192|      1|                "not called: {}",
+  193|      1|                if is_true { "check" } else { "me" }
+                                                            ^0
+  194|      1|            )
+  195|       |    ;
+  196|       |
+  197|      1|    let short_used_covered_closure_line_break_block_embedded_branch =
+  198|      1|        | _unused_arg: u8 |
+  199|      1|        {
+  200|      1|            println!(
+  201|      1|                "not called: {}",
+  202|      1|                if is_true { "check" } else { "me" }
+                                                            ^0
+  203|       |            )
+  204|      1|        }
+  205|       |    ;
+  206|       |
+  207|      1|    if is_false {
+  208|      0|        short_used_not_covered_closure_macro(0);
+  209|      0|        short_used_not_covered_closure_line_break_no_block_embedded_branch(0);
+  210|      0|        short_used_not_covered_closure_line_break_block_embedded_branch(0);
+  211|      1|    }
+  212|      1|    short_used_covered_closure_macro(0);
+  213|      1|    short_used_covered_closure_line_break_no_block_embedded_branch(0);
+  214|      1|    short_used_covered_closure_line_break_block_embedded_branch(0);
+  215|      1|}
 
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
index a030035f13b..87f7014760e 100644
--- 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
@@ -14,15 +14,15 @@
    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"))
+   17|       |        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+   18|       |            let message = format!($error_message, e);
+   19|       |            if message.len() > 0 {
+   20|       |                println!("{}", message);
+   21|       |                Ok(String::from("ok"))
    22|       |            } else {
-   23|      0|                bail!("error");
+   23|       |                bail!("error");
    24|       |            }
-   25|      0|        })
+   25|       |        })
    26|       |    };
    27|       |}
    28|       |
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
index a954eb30378..2b5418132c3 100644
--- 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
@@ -14,15 +14,15 @@
    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"))
+   17|       |        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+   18|       |            let message = format!($error_message, e);
+   19|       |            if message.len() > 0 {
+   20|       |                println!("{}", message);
+   21|       |                Ok(String::from("ok"))
    22|       |            } else {
-   23|      0|                bail!("error");
+   23|       |                bail!("error");
    24|       |            }
-   25|      0|        })
+   25|       |        })
    26|       |    };
    27|       |}
    28|       |
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
index c4a7b0cc7e9..324b9138c4d 100644
--- 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
@@ -11,8 +11,27 @@
    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|}
+   14|       |#[no_coverage]
+   15|       |fn do_not_add_coverage_not_called() {
+   16|       |    println!("not called and not covered");
+   17|       |}
+   18|       |
+   19|      1|fn add_coverage_1() {
+   20|      1|    println!("called and covered");
+   21|      1|}
+   22|       |
+   23|      1|fn add_coverage_2() {
+   24|      1|    println!("called and covered");
+   25|      1|}
+   26|       |
+   27|      0|fn add_coverage_not_called() {
+   28|      0|    println!("not called but covered");
+   29|      0|}
+   30|       |
+   31|      1|fn main() {
+   32|      1|    do_not_add_coverage_1();
+   33|      1|    do_not_add_coverage_2();
+   34|      1|    add_coverage_1();
+   35|      1|    add_coverage_2();
+   36|      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
deleted file mode 100644
index 16eaf7c858c..00000000000
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-    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.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt
index c77ee5ddc20..114507dc9fd 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt
@@ -29,22 +29,4 @@
    29|       |//   2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the
    30|       |//      normal program exit cleanup, including writing out the current values of the coverage
    31|       |//      counters.
-   32|       |//   3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does
-   33|       |//      not show coverage of the `if countdown == 1` branch in `main()` that calls
-   34|       |//      `might_panic(true)` (causing the call to `panic!()`).
-   35|       |//   4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears
-   36|       |//      "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators
-   37|       |//      as non-branching, because when a program executes normally, they always are. Errors handled
-   38|       |//      via the try `?` operator produce error handling branches that *are* treated as branches in
-   39|       |//      coverage results. By treating calls without try `?` operators as non-branching (assumed to
-   40|       |//      return normally and continue) the coverage graph can be simplified, producing smaller,
-   41|       |//      faster binaries, and cleaner coverage results.
-   42|       |//   5. The reason the coverage results actually show `panic!()` was called is most likely because
-   43|       |//      `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or
-   44|       |//      `Terminator`s that execute with a coverage counter before the panic and unwind occur.
-   45|       |//   6. Since the common practice is not to use `panic!()` for error handling, the coverage
-   46|       |//      implementation avoids incurring an additional cost (in program size and execution time) to
-   47|       |//      improve coverage results for an event that is generally not "supposed" to happen.
-   48|       |//   7. FIXME(#78544): This issue describes a feature request for a proposed option to enable
-   49|       |//      more accurate coverage results for tests that intentionally panic.
 
diff --git a/src/test/run-make-fulldeps/coverage/async2.rs b/src/test/run-make-fulldeps/coverage/async2.rs
index 6171d95ff55..959d48ce9db 100644
--- a/src/test/run-make-fulldeps/coverage/async2.rs
+++ b/src/test/run-make-fulldeps/coverage/async2.rs
@@ -14,9 +14,9 @@ fn non_async_func() {
     }
 }
 
-// FIXME(#83985): The auto-generated closure in an async function is failing to include
-// the println!() and `let` assignment lines in the coverage code region(s), as it does in the
-// non-async function above, unless the `println!()` is inside a covered block.
+
+
+
 async fn async_func() {
     println!("async_func was covered");
     let b = true;
@@ -25,9 +25,9 @@ async fn async_func() {
     }
 }
 
-// FIXME(#83985): As above, this async function only has the `println!()` macro call, which is not
-// showing coverage, so the entire async closure _appears_ uncovered; but this is not exactly true.
-// It's only certain kinds of lines and/or their context that results in missing coverage.
+
+
+
 async fn async_func_just_println() {
     println!("async_func_just_println was covered");
 }
diff --git a/src/test/run-make-fulldeps/coverage/closure.rs b/src/test/run-make-fulldeps/coverage/closure.rs
index 796512f0c71..32ec0bcdf8c 100644
--- a/src/test/run-make-fulldeps/coverage/closure.rs
+++ b/src/test/run-make-fulldeps/coverage/closure.rs
@@ -130,14 +130,14 @@ fn main() {
     let mut countdown = 10;
     let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
 
-    // Macros can sometimes confuse the coverage results. Compare this next assignment, with an
-    // unused closure that invokes the `println!()` macro, with the closure assignment above, that
-    // does not use a macro. The closure above correctly shows `0` executions.
-    let _short_unused_closure = | _unused_arg: u8 | println!("not called");
-    // The closure assignment above is executed, with a line count of `1`, but the `println!()`
-    // could not have been called, and yet, there is no indication that it wasn't...
-
-    // ...but adding block braces gives the expected result, showing the block was not executed.
+
+    let short_used_covered_closure_macro = | used_arg: u8 | println!("called");
+    let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called");
+    let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called");
+
+
+
+
     let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") };
 
     let _shortish_unused_closure = | _unused_arg: u8 | {
@@ -152,4 +152,64 @@ fn main() {
         _unused_arg: u8
     | { println!("not called") }
     ;
+
+
+
+
+
+    let _short_unused_closure_line_break_no_block = | _unused_arg: u8 |
+println!("not called")
+    ;
+
+    let _short_unused_closure_line_break_no_block2 =
+        | _unused_arg: u8 |
+            println!(
+                "not called"
+            )
+    ;
+
+    let short_used_not_covered_closure_line_break_no_block_embedded_branch =
+        | _unused_arg: u8 |
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+    ;
+
+    let short_used_not_covered_closure_line_break_block_embedded_branch =
+        | _unused_arg: u8 |
+        {
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+        }
+    ;
+
+    let short_used_covered_closure_line_break_no_block_embedded_branch =
+        | _unused_arg: u8 |
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+    ;
+
+    let short_used_covered_closure_line_break_block_embedded_branch =
+        | _unused_arg: u8 |
+        {
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+        }
+    ;
+
+    if is_false {
+        short_used_not_covered_closure_macro(0);
+        short_used_not_covered_closure_line_break_no_block_embedded_branch(0);
+        short_used_not_covered_closure_line_break_block_embedded_branch(0);
+    }
+    short_used_covered_closure_macro(0);
+    short_used_covered_closure_line_break_no_block_embedded_branch(0);
+    short_used_covered_closure_line_break_block_embedded_branch(0);
 }
diff --git a/src/test/run-make-fulldeps/coverage/closure_macro.rs b/src/test/run-make-fulldeps/coverage/closure_macro.rs
index 10e434007b8..5e3b00d1ef5 100644
--- a/src/test/run-make-fulldeps/coverage/closure_macro.rs
+++ b/src/test/run-make-fulldeps/coverage/closure_macro.rs
@@ -14,7 +14,7 @@ macro_rules! bail {
 
 macro_rules! on_error {
     ($value:expr, $error_message:expr) => {
-        $value.or_else(|e| {
+        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
             let message = format!($error_message, e);
             if message.len() > 0 {
                 println!("{}", message);
diff --git a/src/test/run-make-fulldeps/coverage/closure_macro_async.rs b/src/test/run-make-fulldeps/coverage/closure_macro_async.rs
index bcdfd11f899..e3e89e9c8b3 100644
--- a/src/test/run-make-fulldeps/coverage/closure_macro_async.rs
+++ b/src/test/run-make-fulldeps/coverage/closure_macro_async.rs
@@ -14,7 +14,7 @@ macro_rules! bail {
 
 macro_rules! on_error {
     ($value:expr, $error_message:expr) => {
-        $value.or_else(|e| {
+        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
             let message = format!($error_message, e);
             if message.len() > 0 {
                 println!("{}", message);
diff --git a/src/test/run-make-fulldeps/coverage/no_cov_crate.rs b/src/test/run-make-fulldeps/coverage/no_cov_crate.rs
index 300570db7e8..6f8586d9f5c 100644
--- a/src/test/run-make-fulldeps/coverage/no_cov_crate.rs
+++ b/src/test/run-make-fulldeps/coverage/no_cov_crate.rs
@@ -11,7 +11,26 @@ fn do_not_add_coverage_2() {
     println!("called but not covered");
 }
 
+#[no_coverage]
+fn do_not_add_coverage_not_called() {
+    println!("not called and not covered");
+}
+
+fn add_coverage_1() {
+    println!("called and covered");
+}
+
+fn add_coverage_2() {
+    println!("called and covered");
+}
+
+fn add_coverage_not_called() {
+    println!("not called but covered");
+}
+
 fn main() {
     do_not_add_coverage_1();
     do_not_add_coverage_2();
+    add_coverage_1();
+    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
deleted file mode 100644
index e19a2c4a872..00000000000
--- a/src/test/run-make-fulldeps/coverage/no_cov_func.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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/panic_unwind.rs b/src/test/run-make-fulldeps/coverage/panic_unwind.rs
index b6c0c080762..03128c2cce6 100644
--- a/src/test/run-make-fulldeps/coverage/panic_unwind.rs
+++ b/src/test/run-make-fulldeps/coverage/panic_unwind.rs
@@ -29,21 +29,3 @@ fn main() -> Result<(), u8> {
 //   2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the
 //      normal program exit cleanup, including writing out the current values of the coverage
 //      counters.
-//   3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does
-//      not show coverage of the `if countdown == 1` branch in `main()` that calls
-//      `might_panic(true)` (causing the call to `panic!()`).
-//   4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears
-//      "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators
-//      as non-branching, because when a program executes normally, they always are. Errors handled
-//      via the try `?` operator produce error handling branches that *are* treated as branches in
-//      coverage results. By treating calls without try `?` operators as non-branching (assumed to
-//      return normally and continue) the coverage graph can be simplified, producing smaller,
-//      faster binaries, and cleaner coverage results.
-//   5. The reason the coverage results actually show `panic!()` was called is most likely because
-//      `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or
-//      `Terminator`s that execute with a coverage counter before the panic and unwind occur.
-//   6. Since the common practice is not to use `panic!()` for error handling, the coverage
-//      implementation avoids incurring an additional cost (in program size and execution time) to
-//      improve coverage results for an event that is generally not "supposed" to happen.
-//   7. FIXME(#78544): This issue describes a feature request for a proposed option to enable
-//      more accurate coverage results for tests that intentionally panic.
diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
index f287f87408c..de215b2163b 100644
--- a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
+++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
@@ -10,7 +10,6 @@ note: the lint level is defined here
 LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: aborting due to previous error
 
diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
index 94d6d461651..195aaca32a2 100644
--- a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
+++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
@@ -10,47 +10,36 @@ note: the lint level is defined here
 LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `bar`
   --> $DIR/unknown-disambiguator.rs:3:35
    |
 LL | //! Linking to [foo@banana] and [`bar@banana!()`].
    |                                   ^^^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `foo`
   --> $DIR/unknown-disambiguator.rs:9:34
    |
 LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
    |                                  ^^^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `foo`
   --> $DIR/unknown-disambiguator.rs:9:48
    |
 LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
    |                                                ^^^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator ``
   --> $DIR/unknown-disambiguator.rs:6:31
    |
 LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
    |                               ^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator ``
   --> $DIR/unknown-disambiguator.rs:6:57
    |
 LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
    |                                                         ^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: aborting due to 6 previous errors
 
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/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs
index bb6af7995a0..7bfa922185b 100644
--- a/src/test/rustdoc/assoc-consts.rs
+++ b/src/test/rustdoc/assoc-consts.rs
@@ -88,12 +88,14 @@ impl Qux for Bar {
     /// Docs for QUX1 in impl.
     const QUX1: i8 = 5;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
-    // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT12 in trait."
+    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
     const QUX_DEFAULT0: u16 = 6;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
     // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
     /// Docs for QUX_DEFAULT1 in impl.
     const QUX_DEFAULT1: i16 = 7;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
-    // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT2 in trait."
+    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
 }
diff --git a/src/test/rustdoc/auxiliary/trait-alias-mention.rs b/src/test/rustdoc/auxiliary/trait-alias-mention.rs
new file mode 100644
index 00000000000..6df06c87a09
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/trait-alias-mention.rs
@@ -0,0 +1,3 @@
+#![feature(trait_alias)]
+
+pub trait SomeAlias = std::fmt::Debug + std::marker::Copy;
diff --git a/src/test/rustdoc/auxiliary/trait-visibility.rs b/src/test/rustdoc/auxiliary/trait-visibility.rs
new file mode 100644
index 00000000000..1e8d0b8e02a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/trait-visibility.rs
@@ -0,0 +1,3 @@
+pub trait Bar {
+    fn foo();
+}
diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs
index 7eb3e43cb11..8fc01c3f04c 100644
--- a/src/test/rustdoc/inline_cross/assoc-items.rs
+++ b/src/test/rustdoc/inline_cross/assoc-items.rs
@@ -16,15 +16,18 @@ extern crate assoc_items;
 // @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
 // @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
 // @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
-// @has - '//*[@class="docblock hidden"]' 'docs for ConstWithDefault'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//details/details/div[@class="docblock"]' 'docs for ConstWithDefault'
 // @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
 // @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
 // @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
-// @has - '//*[@class="docblock hidden"]' 'docs for TypeWithDefault'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//details/details/div[@class="docblock"]' 'docs for TypeWithDefault'
 // @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
 // @has - '//*[@class="docblock"]' 'dox for method_no_default'
 // @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
-// @has - '//*[@class="docblock hidden"]' 'docs for method_with_default'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for method_with_default'
+// @has - '//details/details/div[@class="docblock"]' 'docs for method_with_default'
 pub use assoc_items::MyStruct;
 
 // @has foo/trait.MyTrait.html
diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
index 4591bb526ae..cc0596c70ce 100644
--- a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
+++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
@@ -8,5 +8,6 @@ extern crate impl_inline_without_trait;
 
 // @has 'foo/struct.MyStruct.html'
 // @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
-// @has - '//*[@class="docblock hidden"]' 'docs for my_trait_method'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for my_trait_method'
+// @has - '//details/details/div[@class="docblock"]' 'docs for my_trait_method'
 pub use impl_inline_without_trait::MyStruct;
diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs
index 11ddab5f7ff..776a191ceef 100644
--- a/src/test/rustdoc/manual_impl.rs
+++ b/src/test/rustdoc/manual_impl.rs
@@ -24,10 +24,13 @@ pub trait T {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
 // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait c_method definition.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
 // @!has - '//*[@class="docblock"]' 'There is another line'
-// @has - '//*[@class="docblock hidden"]' 'Read more'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Read more'
 pub struct S1(usize);
 
 /// Docs associated with the S1 trait implementation.
@@ -42,9 +45,10 @@ impl T for S1 {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
-// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
+// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
 pub struct S2(usize);
 
 /// Docs associated with the S2 trait implementation.
@@ -61,9 +65,10 @@ impl T for S2 {
 }
 
 // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has  - '//*[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @has  - '//*[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait a_method definition.'
+// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
 pub struct S3(usize);
 
 /// Docs associated with the S3 trait implementation.
diff --git a/src/test/rustdoc/trait-alias-mention.rs b/src/test/rustdoc/trait-alias-mention.rs
new file mode 100644
index 00000000000..6da0dc68785
--- /dev/null
+++ b/src/test/rustdoc/trait-alias-mention.rs
@@ -0,0 +1,10 @@
+// aux-build:trait-alias-mention.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+extern crate trait_alias_mention;
+
+// @has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias'
+pub fn mention_alias_in_bounds<T: trait_alias_mention::SomeAlias>() {
+}
diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs
index 3bcaa3bb673..931691db3e6 100644
--- a/src/test/rustdoc/trait-impl.rs
+++ b/src/test/rustdoc/trait-impl.rs
@@ -21,26 +21,27 @@ pub trait Trait {
 pub struct Struct;
 
 impl Trait for Struct {
-    // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../div/p' 'Some long docs'
-    // @!has - '//*[@id="method.a"]/../div/p' 'link will be added'
-    // @has - '//*[@id="method.a"]/../div/p/a' 'Read more'
-    // @has - '//*[@id="method.a"]/../div/p/a/@href' 'trait.Trait.html'
+    // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'Some long docs'
+    // @!has - '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'link will be added'
+    // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a' 'Read more'
+    // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.a'
     fn a() {}
 
-    // @has trait_impl/struct.Struct.html '//*[@id="method.b"]/../div/p' 'These docs contain'
-    // @has - '//*[@id="method.b"]/../div/p/a' 'reference link'
-    // @has - '//*[@id="method.b"]/../div/p/a/@href' 'https://example.com'
-    // @has - '//*[@id="method.b"]/../div/p/a' 'Read more'
-    // @has - '//*[@id="method.b"]/../div/p/a/@href' 'trait.Trait.html'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p' 'These docs contain'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'reference link'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'https://example.com'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'Read more'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.b'
     fn b() {}
 
-    // @!has trait_impl/struct.Struct.html '//*[@id="method.c"]/../div/p' 'code block'
-    // @has - '//*[@id="method.c"]/../div/p/a' 'Read more'
-    // @has - '//*[@id="method.c"]/../div/p/a/@href' 'trait.Trait.html'
+    // @!has - '//*[@id="method.c"]/../../div[@class="docblock"]/p' 'code block'
+    // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a' 'Read more'
+    // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.c'
     fn c() {}
 
-    // @has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p' \
-    //   'Escaped formatting a*b*c* works'
-    // @!has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p/em'
+    // @has - '//*[@id="method.d"]/../../div[@class="docblock"]/p' 'Escaped formatting a*b*c* works'
+    // @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em'
     fn d() {}
+
+    // @has - '//*[@id="impl-Trait"]/code/a/@href' 'trait.Trait.html'
 }
diff --git a/src/test/rustdoc/trait-visibility.rs b/src/test/rustdoc/trait-visibility.rs
new file mode 100644
index 00000000000..8ba3ee03a74
--- /dev/null
+++ b/src/test/rustdoc/trait-visibility.rs
@@ -0,0 +1,8 @@
+// aux-build:trait-visibility.rs
+
+#![crate_name = "foo"]
+
+extern crate trait_visibility;
+
+// @has foo/trait.Bar.html '//a[@href="#tymethod.foo"]/..' "fn foo()"
+pub use trait_visibility::Bar;
diff --git a/src/test/rustdoc/trait_alias.rs b/src/test/rustdoc/trait_alias.rs
index 98b8d879ac0..6cd4a1a0afa 100644
--- a/src/test/rustdoc/trait_alias.rs
+++ b/src/test/rustdoc/trait_alias.rs
@@ -19,3 +19,5 @@ pub trait CopyAlias = Copy;
 pub trait Alias2 = Copy + Debug;
 // @has foo/traitalias.Foo.html '//section[@id="main"]/pre' 'trait Foo<T> = Into<T> + Debug;'
 pub trait Foo<T> = Into<T> + Debug;
+// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
+pub fn bar<T>() where T: Alias2 {}
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/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/cfg/cfg-family.rs b/src/test/ui/cfg/cfg-family.rs
index 912bda4b5e5..c7d196a2aa6 100644
--- a/src/test/ui/cfg/cfg-family.rs
+++ b/src/test/ui/cfg/cfg-family.rs
@@ -1,6 +1,6 @@
-// run-pass
+// build-pass
 // pretty-expanded FIXME #23616
-// ignore-wasm32-bare no target_family
+// ignore-wasm32-bare no bare family
 // ignore-sgx
 
 #[cfg(windows)]
diff --git a/src/test/ui/cfg/cfg-panic.rs b/src/test/ui/cfg/cfg-panic.rs
index dbb5932a9bb..d2113e4f5ec 100644
--- a/src/test/ui/cfg/cfg-panic.rs
+++ b/src/test/ui/cfg/cfg-panic.rs
@@ -1,5 +1,6 @@
 // build-pass
 // compile-flags: -C panic=unwind
+// needs-unwind
 // ignore-emscripten no panic_unwind implementation
 // ignore-wasm32     no panic_unwind implementation
 // ignore-wasm64     no panic_unwind implementation
diff --git a/src/test/ui/cfg/cfg-target-family.rs b/src/test/ui/cfg/cfg-target-family.rs
index b4dc1b73863..90a59fab8e2 100644
--- a/src/test/ui/cfg/cfg-target-family.rs
+++ b/src/test/ui/cfg/cfg-target-family.rs
@@ -1,5 +1,4 @@
-// run-pass
-// ignore-wasm32-bare no target_family
+// build-pass
 // ignore-sgx
 
 // pretty-expanded FIXME #23616
@@ -11,3 +10,7 @@ pub fn main() {
 #[cfg(target_family = "unix")]
 pub fn main() {
 }
+
+#[cfg(target_family="wasm")]
+pub fn main() {
+}
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/const-param-type-depends-on-type-param.full.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr
index a83ee627187..32f7dea8263 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr
@@ -11,6 +11,7 @@ LL | pub struct Dependent<T, const X: T>([(); X]);
    |                      ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr
index a83ee627187..32f7dea8263 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr
@@ -11,6 +11,7 @@ LL | pub struct Dependent<T, const X: T>([(); X]);
    |                      ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-67375.full.stderr b/src/test/ui/const-generics/issue-67375.full.stderr
index 2f004f75de5..0fe65272f1b 100644
--- a/src/test/ui/const-generics/issue-67375.full.stderr
+++ b/src/test/ui/const-generics/issue-67375.full.stderr
@@ -15,6 +15,7 @@ LL | struct Bug<T> {
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issue-67375.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr
index 337e7bc1409..be81fa92129 100644
--- a/src/test/ui/const-generics/issue-67375.min.stderr
+++ b/src/test/ui/const-generics/issue-67375.min.stderr
@@ -14,6 +14,7 @@ LL | struct Bug<T> {
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-67945-1.full.stderr b/src/test/ui/const-generics/issue-67945-1.full.stderr
index 5cdcefe3501..63c50b5ca54 100644
--- a/src/test/ui/const-generics/issue-67945-1.full.stderr
+++ b/src/test/ui/const-generics/issue-67945-1.full.stderr
@@ -19,6 +19,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr
index a3e086ea954..074d36c8ef3 100644
--- a/src/test/ui/const-generics/issue-67945-1.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-1.min.stderr
@@ -23,6 +23,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/issue-67945-2.full.stderr b/src/test/ui/const-generics/issue-67945-2.full.stderr
index 4d96058b395..b9004060231 100644
--- a/src/test/ui/const-generics/issue-67945-2.full.stderr
+++ b/src/test/ui/const-generics/issue-67945-2.full.stderr
@@ -19,6 +19,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr
index 860be4a9b6a..c06df79f842 100644
--- a/src/test/ui/const-generics/issue-67945-2.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-2.min.stderr
@@ -23,6 +23,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 3 previous errors
 
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/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
index f8b9d7adbfe..d845e00694a 100644
--- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
@@ -13,6 +13,7 @@ fn b() {
     //~| ERROR expected trait, found constant `BAR`
     //~| ERROR type provided when a constant was expected
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
 fn c() {
     foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
index ad451fcf65d..857498a1111 100644
--- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
@@ -10,7 +10,7 @@ LL |     foo::<{ BAR + 3 }>();
    |           ^         ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:18:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:19:11
    |
 LL |     foo::<3 + 3>();
    |           ^^^^^
@@ -21,7 +21,7 @@ LL |     foo::<{ 3 + 3 }>();
    |           ^       ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:21:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:22:15
    |
 LL |     foo::<BAR - 3>();
    |               ^ expected one of `,` or `>`
@@ -32,7 +32,7 @@ LL |     foo::<{ BAR - 3 }>();
    |           ^         ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:24:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:25:15
    |
 LL |     foo::<BAR - BAR>();
    |               ^ expected one of `,` or `>`
@@ -43,7 +43,7 @@ LL |     foo::<{ BAR - BAR }>();
    |           ^           ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:27:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:28:11
    |
 LL |     foo::<100 - BAR>();
    |           ^^^^^^^^^
@@ -54,7 +54,7 @@ LL |     foo::<{ 100 - BAR }>();
    |           ^           ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:30:19
+  --> $DIR/const-expression-suggest-missing-braces.rs:31:19
    |
 LL |     foo::<bar<i32>()>();
    |                   ^ expected one of `,` or `>`
@@ -65,7 +65,7 @@ LL |     foo::<{ bar<i32>() }>();
    |           ^            ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:33:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:34:21
    |
 LL |     foo::<bar::<i32>()>();
    |                     ^ expected one of `,` or `>`
@@ -76,7 +76,7 @@ LL |     foo::<{ bar::<i32>() }>();
    |           ^              ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:36:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:37:21
    |
 LL |     foo::<bar::<i32>() + BAR>();
    |                     ^ expected one of `,` or `>`
@@ -87,7 +87,7 @@ LL |     foo::<{ bar::<i32>() + BAR }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:39:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:40:21
    |
 LL |     foo::<bar::<i32>() - BAR>();
    |                     ^ expected one of `,` or `>`
@@ -98,7 +98,7 @@ LL |     foo::<{ bar::<i32>() - BAR }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:42:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:43:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -109,7 +109,7 @@ LL |     foo::<{ BAR - bar::<i32>() }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:45:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:46:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -138,6 +138,8 @@ LL |     foo::<BAR + BAR>();
    |           ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/const-expression-suggest-missing-braces.rs:11:11
diff --git a/src/test/ui/const-generics/unused-type-param-suggestion.rs b/src/test/ui/const-generics/unused-type-param-suggestion.rs
new file mode 100644
index 00000000000..2251512c459
--- /dev/null
+++ b/src/test/ui/const-generics/unused-type-param-suggestion.rs
@@ -0,0 +1,4 @@
+#![crate_type="lib"]
+
+struct Example<N>;
+//~^ ERROR parameter
diff --git a/src/test/ui/const-generics/unused-type-param-suggestion.stderr b/src/test/ui/const-generics/unused-type-param-suggestion.stderr
new file mode 100644
index 00000000000..807065ca109
--- /dev/null
+++ b/src/test/ui/const-generics/unused-type-param-suggestion.stderr
@@ -0,0 +1,12 @@
+error[E0392]: parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:3:16
+   |
+LL | struct Example<N>;
+   |                ^ unused parameter
+   |
+   = help: consider removing `N`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `N` to be a const parameter, use `const N: usize` instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr
index 3affde739af..ce8ab632fcf 100644
--- a/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr
@@ -14,7 +14,7 @@ error: any use of this value will cause an error
    |
 LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to null!
 LL | |     let out_of_bounds_ptr = &ptr[255];
    | |                              ^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
 LL | |
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr
index 63815c46efe..3f49a262ae4 100644
--- a/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr
@@ -14,7 +14,7 @@ error: any use of this value will cause an error
    |
 LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to null!
 LL | |     let out_of_bounds_ptr = &ptr[255];
    | |                              ^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
 LL | |
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.rs b/src/test/ui/consts/const-eval/ub-nonnull.rs
index 0bc406e01a0..75c02a8da19 100644
--- a/src/test/ui/consts/const-eval/ub-nonnull.rs
+++ b/src/test/ui/consts/const-eval/ub-nonnull.rs
@@ -15,7 +15,7 @@ const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
 #[deny(const_err)] // this triggers a `const_err` so validation does not even happen
 const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-    // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+    // Use address-of-element for pointer arithmetic. This could wrap around to null!
     let out_of_bounds_ptr = &ptr[255]; //~ ERROR any use of this value will cause an error
     //~| WARN this was previously accepted by the compiler but is being phased out
     mem::transmute(out_of_bounds_ptr)
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
index 32e13baa3f5..d4a61a46319 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:21:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:24:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
index 8bd4637a80b..17da7c25bac 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:21:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:24:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
diff --git a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
index 62756518a00..33251535be9 100644
--- a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
@@ -6,7 +6,7 @@ LL | |     let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
 LL | |     let another_var = 13;
 LL | |     move || { let _ = bad_ref; let _ = another_var; }
 LL | | };
-   | |__^ type validation failed: encountered a NULL reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+   | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
diff --git a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
index e9fabd9a3bc..de6033702ae 100644
--- a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
@@ -6,7 +6,7 @@ LL | |     let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
 LL | |     let another_var = 13;
 LL | |     move || { let _ = bad_ref; let _ = another_var; }
 LL | | };
-   | |__^ type validation failed: encountered a NULL reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+   | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
index 7ca5c647d88..404ce409d93 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
@@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:135:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inbounds test failed: 0x0 is not a valid pointer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not allowed for this operation
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:139:5
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
index e42c65a1517..39c56542762 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
@@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:135:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inbounds test failed: 0x0 is not a valid pointer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not allowed for this operation
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:139:5
diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr
index eb726f9cb11..d5d213f9c79 100644
--- a/src/test/ui/consts/offset_from_ub.stderr
+++ b/src/test/ui/consts/offset_from_ub.stderr
@@ -74,7 +74,7 @@ error: any use of this value will cause an error
 LL |           unsafe { intrinsics::ptr_offset_from(self, origin) }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                    |
-   |                    inbounds test failed: 0x0 is not a valid pointer
+   |                    null pointer is not allowed for this operation
    |                    inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                    inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:36:14
    | 
diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr
index 082142fbbb7..45203d3e271 100644
--- a/src/test/ui/consts/offset_ub.stderr
+++ b/src/test/ui/consts/offset_ub.stderr
@@ -23,7 +23,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `AFTER_END` at $DIR/offset_ub.rs:7:43
    | 
@@ -41,7 +41,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `AFTER_ARRAY` at $DIR/offset_ub.rs:8:45
    | 
@@ -131,7 +131,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:15:50
    | 
@@ -167,7 +167,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: 0x0 is not a valid pointer
+   |                  pointer arithmetic failed: 0x0 is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:19:50
    | 
diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr
index 9ec009c55c4..62b33000e60 100644
--- a/src/test/ui/consts/ptr_comparisons.stderr
+++ b/src/test/ui/consts/ptr_comparisons.stderr
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset $TWO_WORDS, but is outside bounds of alloc2 which has size $WORD
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset $TWO_WORDS, but is outside bounds of alloc2 which has size $WORD
    |                  inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `_` at $DIR/ptr_comparisons.rs:61:34
    | 
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
new file mode 100644
index 00000000000..7c2babaf7ab
--- /dev/null
+++ b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
@@ -0,0 +1,16 @@
+// edition:2018
+#[deny(bare_trait_objects)]
+
+fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+    //~^ ERROR trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted
+    //~| ERROR trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted
+    let _x: &SomeTrait = todo!();
+    //~^ ERROR trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted
+}
+
+trait SomeTrait {}
+
+fn main() {}
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
new file mode 100644
index 00000000000..ea73e56d843
--- /dev/null
+++ b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
@@ -0,0 +1,34 @@
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/dyn-2018-edition-lint.rs:4:17
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                 ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+note: the lint level is defined here
+  --> $DIR/dyn-2018-edition-lint.rs:2:8
+   |
+LL | #[deny(bare_trait_objects)]
+   |        ^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/dyn-2018-edition-lint.rs:4:35
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                                   ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/dyn-2018-edition-lint.rs:9:14
+   |
+LL |     let _x: &SomeTrait = todo!();
+   |              ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs b/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs
new file mode 100644
index 00000000000..bc1bed8a9a4
--- /dev/null
+++ b/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs
@@ -0,0 +1,12 @@
+// edition:2021
+
+fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+    let _x: &SomeTrait = todo!();
+    //~^ ERROR trait objects must include the `dyn` keyword
+}
+
+trait SomeTrait {}
+
+fn main() {}
diff --git a/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr b/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr
new file mode 100644
index 00000000000..798f48060e7
--- /dev/null
+++ b/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr
@@ -0,0 +1,36 @@
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/dyn-2021-edition-error.rs:6:14
+   |
+LL |     let _x: &SomeTrait = todo!();
+   |              ^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL |     let _x: &dyn SomeTrait = todo!();
+   |              ^^^
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/dyn-2021-edition-error.rs:3:17
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                 ^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL | fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
+   |                 ^^^
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/dyn-2021-edition-error.rs:3:35
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                                   ^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
+   |                                   ^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0782`.
diff --git a/src/test/ui/empty/empty-struct-unit-pat.stderr b/src/test/ui/empty/empty-struct-unit-pat.stderr
index 8ee14a3d01d..a704e1fae49 100644
--- a/src/test/ui/empty/empty-struct-unit-pat.stderr
+++ b/src/test/ui/empty/empty-struct-unit-pat.stderr
@@ -1,84 +1,154 @@
 error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
   --> $DIR/empty-struct-unit-pat.rs:21:9
    |
+LL | struct Empty2;
+   | -------------- `Empty2` defined here
+...
 LL |         Empty2() => ()
-   |         ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^
    | 
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         Empty2 => ()
+   |         ^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
   --> $DIR/empty-struct-unit-pat.rs:24:9
    |
 LL |         XEmpty2() => ()
-   |         ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
+  ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
+LL | pub struct XEmpty2;
+   | ------------------- `XEmpty2` defined here
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XEmpty2 => ()
+   |         ^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
   --> $DIR/empty-struct-unit-pat.rs:28:9
    |
+LL | struct Empty2;
+   | -------------- `Empty2` defined here
+...
 LL |         Empty2(..) => ()
-   |         ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^^^
    | 
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         Empty2 => ()
+   |         ^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
   --> $DIR/empty-struct-unit-pat.rs:32:9
    |
 LL |         XEmpty2(..) => ()
-   |         ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
+  ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
+LL | pub struct XEmpty2;
+   | ------------------- `XEmpty2` defined here
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XEmpty2 => ()
+   |         ^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
   --> $DIR/empty-struct-unit-pat.rs:37:9
    |
+LL |     Empty4
+   |     ------ `E::Empty4` defined here
+...
 LL |         E::Empty4() => ()
-   |         ^^^^^^^^^ not a tuple struct or tuple variant
+   |         ^^^^^^^^^^^ help: use this syntax instead: `E::Empty4`
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4`
   --> $DIR/empty-struct-unit-pat.rs:41:9
    |
 LL |         XE::XEmpty4() => (),
-   |         ^^^^-------
-   |             |
-   |             help: a tuple variant with a similar name exists: `XEmpty5`
+   |         ^^^^^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:8:5
+  ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
+LL |     XEmpty4,
+   |     ------- `XE::XEmpty4` defined here
 LL |     XEmpty5(),
    |     --------- similarly named tuple variant `XEmpty5` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XE::XEmpty4 => (),
+   |         ^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5() => (),
+   |             ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
   --> $DIR/empty-struct-unit-pat.rs:46:9
    |
+LL |     Empty4
+   |     ------ `E::Empty4` defined here
+...
 LL |         E::Empty4(..) => ()
-   |         ^^^^^^^^^ not a tuple struct or tuple variant
+   |         ^^^^^^^^^^^^^ help: use this syntax instead: `E::Empty4`
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4`
   --> $DIR/empty-struct-unit-pat.rs:50:9
    |
 LL |         XE::XEmpty4(..) => (),
-   |         ^^^^-------
-   |             |
-   |             help: a tuple variant with a similar name exists: `XEmpty5`
+   |         ^^^^^^^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:8:5
+  ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
+LL |     XEmpty4,
+   |     ------- `XE::XEmpty4` defined here
 LL |     XEmpty5(),
    |     --------- similarly named tuple variant `XEmpty5` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XE::XEmpty4 => (),
+   |         ^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5(..) => (),
+   |             ^^^^^^^
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
index 1d43903928b..f89be630eeb 100644
--- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
+++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
@@ -14,6 +14,7 @@ LL | enum MyWeirdOption<T> {
    |                    ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/enum/issue-67945-1.stderr b/src/test/ui/enum/issue-67945-1.stderr
index 32ca94203e6..227899e7535 100644
--- a/src/test/ui/enum/issue-67945-1.stderr
+++ b/src/test/ui/enum/issue-67945-1.stderr
@@ -14,6 +14,7 @@ LL | enum Bug<S> {
    |          ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/enum/issue-67945-2.stderr b/src/test/ui/enum/issue-67945-2.stderr
index a738d3b15a5..5a90f00c346 100644
--- a/src/test/ui/enum/issue-67945-2.stderr
+++ b/src/test/ui/enum/issue-67945-2.stderr
@@ -14,6 +14,7 @@ LL | enum Bug<S> {
    |          ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0392.stderr b/src/test/ui/error-codes/E0392.stderr
index 860bf68f018..622402999c3 100644
--- a/src/test/ui/error-codes/E0392.stderr
+++ b/src/test/ui/error-codes/E0392.stderr
@@ -5,6 +5,7 @@ LL | enum Foo<T> { Bar }
    |          ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error
 
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/error-codes/E0583.stderr b/src/test/ui/error-codes/E0583.stderr
index dbe70035595..c7bbbf11499 100644
--- a/src/test/ui/error-codes/E0583.stderr
+++ b/src/test/ui/error-codes/E0583.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `module_that_doesnt_exist`
 LL | mod module_that_doesnt_exist;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs"
+   = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" or "$DIR/module_that_doesnt_exist/mod.rs"
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs
new file mode 100644
index 00000000000..2d00aa2a3cf
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs
@@ -0,0 +1,5 @@
+#[link(name = "foo", modifiers = "")]
+//~^ ERROR: native link modifiers are experimental
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr
new file mode 100644
index 00000000000..20a2d6a26fa
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr
@@ -0,0 +1,12 @@
+error[E0658]: native link modifiers are experimental
+  --> $DIR/feature-gate-native_link_modifiers.rs:1:22
+   |
+LL | #[link(name = "foo", modifiers = "")]
+   |                      ^^^^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers)]` 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-native_link_modifiers_as_needed.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs
new file mode 100644
index 00000000000..4cf8067592e
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+as-needed")]
+//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr
new file mode 100644
index 00000000000..08ce807851b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="as-needed")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+as-needed")]
+   |                                  ^^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_as_needed)]` 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-native_link_modifiers_bundle.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs
new file mode 100644
index 00000000000..b2b1dc28e47
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+bundle")]
+//~^ ERROR: `#[link(modifiers="bundle")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr
new file mode 100644
index 00000000000..b3e22b0644a
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="bundle")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_bundle.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+bundle")]
+   |                                  ^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_bundle)]` 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-native_link_modifiers_verbatim.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs
new file mode 100644
index 00000000000..042ce0b3f65
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+verbatim")]
+//~^ ERROR: `#[link(modifiers="verbatim")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr
new file mode 100644
index 00000000000..8159416edfa
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="verbatim")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_verbatim.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+verbatim")]
+   |                                  ^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_verbatim)]` 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-native_link_modifiers_whole_archive.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs
new file mode 100644
index 00000000000..ca801e59114
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+whole-archive")]
+//~^ ERROR: `#[link(modifiers="whole-archive")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr
new file mode 100644
index 00000000000..cacaa789ecb
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="whole-archive")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_whole_archive.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+whole-archive")]
+   |                                  ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_whole_archive)]` 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
index c6b79f9a431..fd4c6f76059 100644
--- a/src/test/ui/feature-gates/feature-gate-no_coverage.rs
+++ b/src/test/ui/feature-gates/feature-gate-no_coverage.rs
@@ -1,8 +1,13 @@
 #![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() {}
+#[derive(PartialEq, Eq)] // ensure deriving `Eq` does not enable `feature(no_coverage)`
+struct Foo {
+    a: u8,
+    b: u32,
+}
 
 #[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature
-fn requires_feature_no_coverage() {}
+fn requires_feature_no_coverage() -> bool {
+    let bar = Foo { a: 0, b: 0 };
+    bar == Foo { a: 0, b: 0 }
+}
diff --git a/src/test/ui/feature-gates/feature-gate-no_coverage.stderr b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr
index 04627be4aaf..f7167e0b771 100644
--- a/src/test/ui/feature-gates/feature-gate-no_coverage.stderr
+++ b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr
@@ -1,12 +1,11 @@
 error[E0658]: the `#[no_coverage]` attribute is an experimental feature
-  --> $DIR/feature-gate-no_coverage.rs:7:1
+  --> $DIR/feature-gate-no_coverage.rs:9: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
 
diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr
index d96a48cde9f..301a1e1341e 100644
--- a/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr
@@ -1,3 +1,5 @@
+warning: library kind `static-nobundle` has been superseded by specifying `-bundle` on library kind `static`. Try `static:-bundle`
+
 error[E0658]: kind="static-nobundle" is unstable
    |
    = note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information
diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs
index 05c52f9dbea..e4bfe8e8e05 100644
--- a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs
+++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs
@@ -1,5 +1,6 @@
 #[link(name = "foo", kind = "static-nobundle")]
-//~^ ERROR: kind="static-nobundle" is unstable
+//~^ WARNING: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
+//~^^ ERROR: kind="static-nobundle" is unstable
 extern "C" {}
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
index 3a3c86c3429..9695618207c 100644
--- a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
+++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
@@ -1,3 +1,9 @@
+warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
+  --> $DIR/feature-gate-static-nobundle.rs:1:22
+   |
+LL | #[link(name = "foo", kind = "static-nobundle")]
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0658]: kind="static-nobundle" is unstable
   --> $DIR/feature-gate-static-nobundle.rs:1:1
    |
@@ -7,6 +13,6 @@ LL | #[link(name = "foo", kind = "static-nobundle")]
    = note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information
    = help: add `#![feature(static_nobundle)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr
index 2aab6807aaa..0bd3dbf6863 100644
--- a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |         *(1 as *mut u32) = 42;
    |         ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
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-trait-path-parenthesised-args.rs b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
index bb1f27a17ca..40ed42c9ce0 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
+++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
@@ -11,5 +11,6 @@ fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
   //~^ ERROR: lifetime in trait object type must be followed by `+`
   //~| ERROR: parenthesized generic arguments cannot be used
   //~| WARNING: trait objects without an explicit `dyn` are deprecated
+  //~| WARNING: this was previously accepted by the compiler
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index 20cb6d88287..0e95c54d811 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -26,6 +26,8 @@ LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
    |                             ^^ help: use `dyn`: `dyn 'a`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:8
diff --git a/src/test/ui/inner-static-type-parameter.stderr b/src/test/ui/inner-static-type-parameter.stderr
index 990e4649a58..e4e449e4159 100644
--- a/src/test/ui/inner-static-type-parameter.stderr
+++ b/src/test/ui/inner-static-type-parameter.stderr
@@ -13,6 +13,7 @@ LL | enum Bar<T> { What }
    |          ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/intrinsics/intrinsic-alignment.rs b/src/test/ui/intrinsics/intrinsic-alignment.rs
index 592409ba89f..5a27ea8783a 100644
--- a/src/test/ui/intrinsics/intrinsic-alignment.rs
+++ b/src/test/ui/intrinsics/intrinsic-alignment.rs
@@ -14,6 +14,7 @@ mod rusti {
           target_os = "dragonfly",
           target_os = "emscripten",
           target_os = "freebsd",
+          target_os = "fuchsia",
           target_os = "linux",
           target_os = "macos",
           target_os = "netbsd",
diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr
index 52296042eb4..7bc8efd7e4a 100644
--- a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr
+++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `baz`
 LL | pub mod baz;
    | ^^^^^^^^^^^^
    |
-   = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs"
+   = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" or "$DIR/auxiliary/foo/bar/baz/mod.rs"
 
 error: aborting due to previous error
 
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-17904-2.stderr b/src/test/ui/issues/issue-17904-2.stderr
index 62b7b79538c..259e029113d 100644
--- a/src/test/ui/issues/issue-17904-2.stderr
+++ b/src/test/ui/issues/issue-17904-2.stderr
@@ -5,6 +5,7 @@ LL | struct Foo<T> where T: Copy;
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr
index 7fb1e3f2bba..6bcff7aff2d 100644
--- a/src/test/ui/issues/issue-20413.stderr
+++ b/src/test/ui/issues/issue-20413.stderr
@@ -5,6 +5,7 @@ LL | struct NoData<T>;
    |               ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
   --> $DIR/issue-20413.rs:8:36
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-32004.stderr b/src/test/ui/issues/issue-32004.stderr
index f95afb9c1fd..bf125a8942e 100644
--- a/src/test/ui/issues/issue-32004.stderr
+++ b/src/test/ui/issues/issue-32004.stderr
@@ -21,8 +21,11 @@ LL |         Foo::Baz => {}
 error[E0532]: expected tuple struct or tuple variant, found unit struct `S`
   --> $DIR/issue-32004.rs:16:9
    |
+LL | struct S;
+   | --------- `S` defined here
+...
 LL |         S(()) => {}
-   |         ^ not a tuple struct or tuple variant
+   |         ^^^^^ help: use this syntax instead: `S`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-36299.stderr b/src/test/ui/issues/issue-36299.stderr
index 8e29a925d80..dc24fb353f4 100644
--- a/src/test/ui/issues/issue-36299.stderr
+++ b/src/test/ui/issues/issue-36299.stderr
@@ -13,6 +13,7 @@ LL | struct Foo<'a, A> {}
    |                ^ unused parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-36638.stderr b/src/test/ui/issues/issue-36638.stderr
index e5d6f8ec7ad..733fc4af534 100644
--- a/src/test/ui/issues/issue-36638.stderr
+++ b/src/test/ui/issues/issue-36638.stderr
@@ -17,6 +17,7 @@ LL | struct Foo<Self>(Self);
    |            ^^^^ unused parameter
    |
    = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `Self` to be a const parameter, use `const Self: usize` instead
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr
index 895479986f1..82bb51028c9 100644
--- a/src/test/ui/issues/issue-37534.stderr
+++ b/src/test/ui/issues/issue-37534.stderr
@@ -22,6 +22,7 @@ LL | struct Foo<T: ?Hash> { }
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/issues/issue-47412.stderr b/src/test/ui/issues/issue-47412.stderr
index 0f003c44b70..aebcbf07463 100644
--- a/src/test/ui/issues/issue-47412.stderr
+++ b/src/test/ui/issues/issue-47412.stderr
@@ -12,7 +12,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     match *ptr {}
    |           ^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to 2 previous errors
 
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/issues/issue-70093.rs b/src/test/ui/issues/issue-70093.rs
index 95ab86ebcb1..fbe68fb9379 100644
--- a/src/test/ui/issues/issue-70093.rs
+++ b/src/test/ui/issues/issue-70093.rs
@@ -1,6 +1,7 @@
 // run-pass
 // compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
 // ignore-windows - this will probably only work on unixish systems
+// ignore-fuchsia - missing __libc_start_main for some reason (#84733)
 
 #[link(name = "some-random-non-existent-library", kind = "static")]
 extern "C" {}
diff --git a/src/test/ui/issues/issue-pr29383.stderr b/src/test/ui/issues/issue-pr29383.stderr
index e92fd6c2fdc..57783d75ba1 100644
--- a/src/test/ui/issues/issue-pr29383.stderr
+++ b/src/test/ui/issues/issue-pr29383.stderr
@@ -1,14 +1,20 @@
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::A`
   --> $DIR/issue-pr29383.rs:9:14
    |
+LL |     A,
+   |     - `E::A` defined here
+...
 LL |         Some(E::A(..)) => {}
-   |              ^^^^ not a tuple struct or tuple variant
+   |              ^^^^^^^^ help: use this syntax instead: `E::A`
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::B`
   --> $DIR/issue-pr29383.rs:11:14
    |
+LL |     B,
+   |     - `E::B` defined here
+...
 LL |         Some(E::B(..)) => {}
-   |              ^^^^ not a tuple struct or tuple variant
+   |              ^^^^^^^^ help: use this syntax instead: `E::B`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lifetimes/issue-84398.rs b/src/test/ui/lifetimes/issue-84398.rs
new file mode 100644
index 00000000000..1912fa59b79
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-84398.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+pub trait Deserialize<'de>: Sized {}
+pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
+
+pub trait Extensible {
+    type Config;
+}
+
+// The `C` here generates a `C: Sized` candidate
+pub trait Installer<C> {
+    fn init<B: Extensible<Config = C>>(&mut self) -> ()
+    where
+        // This clause generates a `for<'de> C: Sized` candidate
+        B::Config: DeserializeOwned,
+    {
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/bare-trait-objects-path.rs b/src/test/ui/lint/bare-trait-objects-path.rs
index 4c961e998df..74f838e9ed1 100644
--- a/src/test/ui/lint/bare-trait-objects-path.rs
+++ b/src/test/ui/lint/bare-trait-objects-path.rs
@@ -11,8 +11,14 @@ trait Dyn {}
 impl Assoc for dyn Dyn {}
 
 fn main() {
-    Dyn::func(); //~ WARN trait objects without an explicit `dyn` are deprecated
-    ::Dyn::func(); //~ WARN trait objects without an explicit `dyn` are deprecated
-    Dyn::CONST; //~ WARN trait objects without an explicit `dyn` are deprecated
+    Dyn::func();
+    //~^ WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
+    ::Dyn::func();
+    //~^ WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
+    Dyn::CONST;
+    //~^ WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
     let _: Dyn::Ty; //~ ERROR ambiguous associated type
 }
diff --git a/src/test/ui/lint/bare-trait-objects-path.stderr b/src/test/ui/lint/bare-trait-objects-path.stderr
index 0a2dc585828..55c9ea234de 100644
--- a/src/test/ui/lint/bare-trait-objects-path.stderr
+++ b/src/test/ui/lint/bare-trait-objects-path.stderr
@@ -1,5 +1,5 @@
 error[E0223]: ambiguous associated type
-  --> $DIR/bare-trait-objects-path.rs:17:12
+  --> $DIR/bare-trait-objects-path.rs:23:12
    |
 LL |     let _: Dyn::Ty;
    |            ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Trait>::Ty`
@@ -11,18 +11,26 @@ LL |     Dyn::func();
    |     ^^^ help: use `dyn`: `<dyn Dyn>`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/bare-trait-objects-path.rs:15:5
+  --> $DIR/bare-trait-objects-path.rs:17:5
    |
 LL |     ::Dyn::func();
    |     ^^^^^ help: use `dyn`: `<dyn (::Dyn)>`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/bare-trait-objects-path.rs:16:5
+  --> $DIR/bare-trait-objects-path.rs:20:5
    |
 LL |     Dyn::CONST;
    |     ^^^ help: use `dyn`: `<dyn Dyn>`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to previous error; 3 warnings emitted
 
diff --git a/src/test/ui/lint/expr_attr_paren_order.rs b/src/test/ui/lint/expr_attr_paren_order.rs
index 65f2b67d22b..e1ec2e951cf 100644
--- a/src/test/ui/lint/expr_attr_paren_order.rs
+++ b/src/test/ui/lint/expr_attr_paren_order.rs
@@ -5,16 +5,14 @@ fn main() {
     // Test that attributes on parens get concatenated
     // in the expected order in the hir folder.
 
-    #[deny(non_snake_case)] (
-        #![allow(non_snake_case)]
+    #[deny(non_snake_case)] #[allow(non_snake_case)] (
         {
             let X = 0;
             let _ = X;
         }
     );
 
-    #[allow(non_snake_case)] (
-        #![deny(non_snake_case)]
+    #[allow(non_snake_case)] #[deny(non_snake_case)] (
         {
             let X = 0; //~ ERROR snake case name
             let _ = X;
diff --git a/src/test/ui/lint/expr_attr_paren_order.stderr b/src/test/ui/lint/expr_attr_paren_order.stderr
index c6b373e3f13..42beed10c19 100644
--- a/src/test/ui/lint/expr_attr_paren_order.stderr
+++ b/src/test/ui/lint/expr_attr_paren_order.stderr
@@ -1,14 +1,14 @@
 error: variable `X` should have a snake case name
-  --> $DIR/expr_attr_paren_order.rs:19:17
+  --> $DIR/expr_attr_paren_order.rs:17:17
    |
 LL |             let X = 0;
    |                 ^ help: convert the identifier to snake case (notice the capitalization): `x`
    |
 note: the lint level is defined here
-  --> $DIR/expr_attr_paren_order.rs:17:17
+  --> $DIR/expr_attr_paren_order.rs:15:37
    |
-LL |         #![deny(non_snake_case)]
-   |                 ^^^^^^^^^^^^^^
+LL |     #[allow(non_snake_case)] #[deny(non_snake_case)] (
+   |                                     ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed
index d6e5033a0c4..a1b738e33fa 100644
--- a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed
+++ b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed
@@ -8,12 +8,14 @@ fn main() {
     match despondency {
         1..=2 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 
     match &despondency {
         &(1..=2) => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 }
diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.rs b/src/test/ui/lint/inclusive-range-pattern-syntax.rs
index 773eea14fd7..d3ebbf38e1c 100644
--- a/src/test/ui/lint/inclusive-range-pattern-syntax.rs
+++ b/src/test/ui/lint/inclusive-range-pattern-syntax.rs
@@ -8,12 +8,14 @@ fn main() {
     match despondency {
         1...2 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 
     match &despondency {
         &1...2 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 }
diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr
index 19fe9ed892a..ba4ae208e39 100644
--- a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr
+++ b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr
@@ -9,12 +9,17 @@ note: the lint level is defined here
    |
 LL | #![warn(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: `...` range patterns are deprecated
-  --> $DIR/inclusive-range-pattern-syntax.rs:15:9
+  --> $DIR/inclusive-range-pattern-syntax.rs:16:9
    |
 LL |         &1...2 => {}
    |         ^^^^^^ help: use `..=` for an inclusive range: `&(1..=2)`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: 2 warnings emitted
 
diff --git a/src/test/ui/match/match-pattern-field-mismatch-2.stderr b/src/test/ui/match/match-pattern-field-mismatch-2.stderr
index cfffcd13851..ba32d0e99a4 100644
--- a/src/test/ui/match/match-pattern-field-mismatch-2.stderr
+++ b/src/test/ui/match/match-pattern-field-mismatch-2.stderr
@@ -1,8 +1,11 @@
 error[E0532]: expected tuple struct or tuple variant, found unit variant `Color::NoColor`
   --> $DIR/match-pattern-field-mismatch-2.rs:12:11
    |
+LL |         NoColor,
+   |         ------- `Color::NoColor` defined here
+...
 LL |           Color::NoColor(_) => { }
-   |           ^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |           ^^^^^^^^^^^^^^^^^ help: use this syntax instead: `Color::NoColor`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/meta/revision-bad.rs b/src/test/ui/meta/revision-bad.rs
index 01f1518c1c6..37ddbe99a9f 100644
--- a/src/test/ui/meta/revision-bad.rs
+++ b/src/test/ui/meta/revision-bad.rs
@@ -4,6 +4,7 @@
 // run-fail
 // revisions: foo bar
 // should-fail
+// needs-run-enabled
 //[foo] error-pattern:bar
 //[bar] error-pattern:foo
 
diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
index 91b3fe15c4b..31e4206a546 100644
--- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
+++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `missing`
 LL | mod missing;
    | ^^^^^^^^^^^^
    |
-   = help: to create the module `missing`, create file "$DIR/foo/missing.rs"
+   = help: to create the module `missing`, create file "$DIR/foo/missing.rs" or "$DIR/foo/missing/mod.rs"
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr
index f519de46c76..9d252398b7a 100644
--- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr
+++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `missing`
 LL |     mod missing;
    |     ^^^^^^^^^^^^
    |
-   = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs"
+   = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" or "$DIR/foo_inline/inline/missing/mod.rs"
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr b/src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr
index 3a3d2e2dddd..a2c99396987 100644
--- a/src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr
+++ b/src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr
@@ -1,4 +1,4 @@
-error[E0761]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs
+error[E0761]: file for module `mod_file_disambig_aux` found at both "$DIR/mod_file_disambig_aux.rs" and "$DIR/mod_file_disambig_aux/mod.rs"
   --> $DIR/mod_file_disambig.rs:1:1
    |
 LL | mod mod_file_disambig_aux;
diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.rs b/src/test/ui/native-library-link-flags/empty-kind-1.rs
new file mode 100644
index 00000000000..6f93d38ca93
--- /dev/null
+++ b/src/test/ui/native-library-link-flags/empty-kind-1.rs
@@ -0,0 +1,6 @@
+// Unspecified kind should fail with an error
+
+// compile-flags: -l =mylib
+// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
+
+fn main() {}
diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.stderr b/src/test/ui/native-library-link-flags/empty-kind-1.stderr
new file mode 100644
index 00000000000..2a4a82d538f
--- /dev/null
+++ b/src/test/ui/native-library-link-flags/empty-kind-1.stderr
@@ -0,0 +1,2 @@
+error: unknown library kind ``, expected one of dylib, framework, or static
+
diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.rs b/src/test/ui/native-library-link-flags/empty-kind-2.rs
new file mode 100644
index 00000000000..c0c35577057
--- /dev/null
+++ b/src/test/ui/native-library-link-flags/empty-kind-2.rs
@@ -0,0 +1,6 @@
+// Unspecified kind should fail with an error
+
+// compile-flags: -l :+bundle=mylib
+// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
+
+fn main() {}
diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.stderr b/src/test/ui/native-library-link-flags/empty-kind-2.stderr
new file mode 100644
index 00000000000..2a4a82d538f
--- /dev/null
+++ b/src/test/ui/native-library-link-flags/empty-kind-2.stderr
@@ -0,0 +1,2 @@
+error: unknown library kind ``, expected one of dylib, framework, or static
+
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/panic-handler/weak-lang-item.rs b/src/test/ui/panic-handler/weak-lang-item.rs
index 3fa3822831b..df31e614cf8 100644
--- a/src/test/ui/panic-handler/weak-lang-item.rs
+++ b/src/test/ui/panic-handler/weak-lang-item.rs
@@ -1,6 +1,7 @@
 // aux-build:weak-lang-items.rs
 // error-pattern: `#[panic_handler]` function required, but not found
 // error-pattern: language item required, but not found: `eh_personality`
+// needs-unwind since it affects the error output
 // ignore-emscripten compiled with panic=abort, personality not required
 
 #![no_std]
diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr
index 68e3e21df3e..1f14b20e451 100644
--- a/src/test/ui/panic-handler/weak-lang-item.stderr
+++ b/src/test/ui/panic-handler/weak-lang-item.stderr
@@ -1,5 +1,5 @@
 error[E0259]: the name `core` is defined multiple times
-  --> $DIR/weak-lang-item.rs:8:1
+  --> $DIR/weak-lang-item.rs:9:1
    |
 LL | extern crate core;
    | ^^^^^^^^^^^^^^^^^^ `core` reimported here
diff --git a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs
index f8368ff6900..58a90a592c4 100644
--- a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs
+++ b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs
@@ -1,5 +1,6 @@
 // build-fail
 // compile-flags:-C panic=abort -C prefer-dynamic
+// needs-unwind
 // ignore-musl - no dylibs here
 // ignore-emscripten
 // ignore-sgx no dynamic lib support
diff --git a/src/test/ui/panic-runtime/lto-unwind.rs b/src/test/ui/panic-runtime/lto-unwind.rs
index 6f39b76526b..24048ebe008 100644
--- a/src/test/ui/panic-runtime/lto-unwind.rs
+++ b/src/test/ui/panic-runtime/lto-unwind.rs
@@ -2,6 +2,7 @@
 #![allow(unused_variables)]
 
 // compile-flags:-C lto -C panic=unwind
+// needs-unwind
 // no-prefer-dynamic
 // ignore-emscripten no processes
 // ignore-sgx no processes
diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs
index 1848c986e36..622535a75af 100644
--- a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs
+++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs
@@ -1,4 +1,5 @@
 // build-fail
+// needs-unwind
 // aux-build:panic-runtime-unwind.rs
 // aux-build:panic-runtime-abort.rs
 // aux-build:wants-panic-runtime-unwind.rs
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
index 894a5eb38b8..c48caaf0790 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
@@ -1,4 +1,5 @@
 // build-fail
+// needs-unwind
 // error-pattern:is incompatible with this crate's strategy of `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs
index 5955075bae5..7a2e48e2f10 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs
@@ -1,4 +1,5 @@
 // build-fail
+// needs-unwind
 // error-pattern:is incompatible with this crate's strategy of `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:wants-panic-runtime-abort.rs
diff --git a/src/test/ui/parser/issue-68890-2.rs b/src/test/ui/parser/issue-68890-2.rs
index ae022460468..88527cc8783 100644
--- a/src/test/ui/parser/issue-68890-2.rs
+++ b/src/test/ui/parser/issue-68890-2.rs
@@ -4,3 +4,4 @@ type X<'a> = (?'a) +;
 //~^ ERROR `?` may only modify trait bounds, not lifetime bounds
 //~| ERROR at least one trait is required for an object type
 //~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
diff --git a/src/test/ui/parser/issue-68890-2.stderr b/src/test/ui/parser/issue-68890-2.stderr
index e51c2c0e842..37f38365b01 100644
--- a/src/test/ui/parser/issue-68890-2.stderr
+++ b/src/test/ui/parser/issue-68890-2.stderr
@@ -11,6 +11,8 @@ LL | type X<'a> = (?'a) +;
    |              ^^^^^^^ help: use `dyn`: `dyn (?'a) +`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/issue-68890-2.rs:3:14
diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.rs b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs
index 0b10a5f6f4e..0733b2d2df7 100644
--- a/src/test/ui/parser/issue-73568-lifetime-after-mut.rs
+++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs
@@ -14,8 +14,10 @@ mac!('a);
 fn y<'a>(y: &mut 'a + Send) {
     //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
     //~| WARNING trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
     //~| ERROR at least one trait is required for an object type
     let z = y as &mut 'a + Send;
     //~^ ERROR expected value, found trait `Send`
     //~| WARNING trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr
index abb64f7e490..9b05383dd7d 100644
--- a/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr
+++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr
@@ -22,7 +22,7 @@ LL | mac!('a);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0423]: expected value, found trait `Send`
-  --> $DIR/issue-73568-lifetime-after-mut.rs:18:28
+  --> $DIR/issue-73568-lifetime-after-mut.rs:19:28
    |
 LL |     let z = y as &mut 'a + Send;
    |                            ^^^^ not a value
@@ -34,12 +34,17 @@ LL | fn y<'a>(y: &mut 'a + Send) {
    |                  ^^ help: use `dyn`: `dyn 'a`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-73568-lifetime-after-mut.rs:18:23
+  --> $DIR/issue-73568-lifetime-after-mut.rs:19:23
    |
 LL |     let z = y as &mut 'a + Send;
    |                       ^^ help: use `dyn`: `dyn 'a`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.rs b/src/test/ui/parser/macro/trait-object-macro-matcher.rs
index 170ac22780b..0428ea0e2c1 100644
--- a/src/test/ui/parser/macro/trait-object-macro-matcher.rs
+++ b/src/test/ui/parser/macro/trait-object-macro-matcher.rs
@@ -12,4 +12,5 @@ fn main() {
     //~^ ERROR lifetime in trait object type must be followed by `+`
     //~| ERROR at least one trait is required for an object type
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr
index b12eedf3581..8ae5611d89d 100644
--- a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr
+++ b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr
@@ -11,6 +11,8 @@ LL |     m!('static);
    |        ^^^^^^^ help: use `dyn`: `dyn 'static`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/trait-object-macro-matcher.rs:11:8
diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr
index 4e08125625f..62456d51880 100644
--- a/src/test/ui/parser/mod_file_not_exist.stderr
+++ b/src/test/ui/parser/mod_file_not_exist.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `not_a_real_file`
 LL | mod not_a_real_file;
    | ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs"
+   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs"
 
 error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux`
   --> $DIR/mod_file_not_exist.rs:7:16
diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr
index 73cdf098b00..d5143dbe982 100644
--- a/src/test/ui/parser/mod_file_not_exist_windows.stderr
+++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `not_a_real_file`
 LL | mod not_a_real_file;
    | ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs"
+   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs"
 
 error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux`
   --> $DIR/mod_file_not_exist_windows.rs:7:16
diff --git a/src/test/ui/parser/recover-range-pats.rs b/src/test/ui/parser/recover-range-pats.rs
index 7412b624b09..a10add6d9e5 100644
--- a/src/test/ui/parser/recover-range-pats.rs
+++ b/src/test/ui/parser/recover-range-pats.rs
@@ -39,20 +39,32 @@ fn inclusive_from_to() {
 }
 
 fn inclusive2_from_to() {
-    if let 0...3 = 0 {} //~ ERROR `...` range patterns are deprecated
-    if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated
-    if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated
-    if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated
+    if let 0...3 = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
+    if let 0...Y = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
+    if let X...3 = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
+    if let X...Y = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
     if let true...Y = 0 {} //~ ERROR only `char` and numeric types
     //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
     if let X...true = 0 {} //~ ERROR only `char` and numeric types
     //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
     if let .0...Y = 0 {} //~ ERROR mismatched types
     //~^ ERROR float literals must have an integer part
+    //~| WARN this was previously accepted by the compiler
     //~| ERROR `...` range patterns are deprecated
     if let X... .0 = 0 {} //~ ERROR mismatched types
     //~^ ERROR float literals must have an integer part
     //~| ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
 
 fn exclusive_from() {
@@ -125,6 +137,7 @@ fn with_macro_expr_var() {
             let $e1..$e2;
             let $e1...$e2;
             //~^ ERROR `...` range patterns are deprecated
+            //~| WARN this was previously accepted by the compiler
             let $e1..=$e2;
         }
     }
diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr
index e351a9783bf..45f6b111e25 100644
--- a/src/test/ui/parser/recover-range-pats.stderr
+++ b/src/test/ui/parser/recover-range-pats.stderr
@@ -23,25 +23,25 @@ LL |     if let X..=.0 = 0 {}
    |                ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:50:12
+  --> $DIR/recover-range-pats.rs:60:12
    |
 LL |     if let .0...Y = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:53:17
+  --> $DIR/recover-range-pats.rs:64:17
    |
 LL |     if let X... .0 = 0 {}
    |                 ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:63:12
+  --> $DIR/recover-range-pats.rs:75:12
    |
 LL |     if let .0.. = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:69:13
+  --> $DIR/recover-range-pats.rs:81:13
    |
 LL |     if let 0..= = 0 {}
    |             ^^^ help: use `..` instead
@@ -49,7 +49,7 @@ LL |     if let 0..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:70:13
+  --> $DIR/recover-range-pats.rs:82:13
    |
 LL |     if let X..= = 0 {}
    |             ^^^ help: use `..` instead
@@ -57,7 +57,7 @@ LL |     if let X..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:71:16
+  --> $DIR/recover-range-pats.rs:83:16
    |
 LL |     if let true..= = 0 {}
    |                ^^^ help: use `..` instead
@@ -65,13 +65,13 @@ LL |     if let true..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:73:12
+  --> $DIR/recover-range-pats.rs:85:12
    |
 LL |     if let .0..= = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:73:14
+  --> $DIR/recover-range-pats.rs:85:14
    |
 LL |     if let .0..= = 0 {}
    |              ^^^ help: use `..` instead
@@ -79,7 +79,7 @@ LL |     if let .0..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:79:13
+  --> $DIR/recover-range-pats.rs:91:13
    |
 LL |     if let 0... = 0 {}
    |             ^^^ help: use `..` instead
@@ -87,7 +87,7 @@ LL |     if let 0... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:80:13
+  --> $DIR/recover-range-pats.rs:92:13
    |
 LL |     if let X... = 0 {}
    |             ^^^ help: use `..` instead
@@ -95,7 +95,7 @@ LL |     if let X... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:81:16
+  --> $DIR/recover-range-pats.rs:93:16
    |
 LL |     if let true... = 0 {}
    |                ^^^ help: use `..` instead
@@ -103,13 +103,13 @@ LL |     if let true... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:83:12
+  --> $DIR/recover-range-pats.rs:95:12
    |
 LL |     if let .0... = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:83:14
+  --> $DIR/recover-range-pats.rs:95:14
    |
 LL |     if let .0... = 0 {}
    |              ^^^ help: use `..` instead
@@ -117,49 +117,49 @@ LL |     if let .0... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:93:15
+  --> $DIR/recover-range-pats.rs:105:15
    |
 LL |     if let .. .0 = 0 {}
    |               ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:103:15
+  --> $DIR/recover-range-pats.rs:115:15
    |
 LL |     if let ..=.0 = 0 {}
    |               ^^ help: must have an integer part: `0.0`
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:109:12
+  --> $DIR/recover-range-pats.rs:121:12
    |
 LL |     if let ...3 = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:111:12
+  --> $DIR/recover-range-pats.rs:123:12
    |
 LL |     if let ...Y = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:113:12
+  --> $DIR/recover-range-pats.rs:125:12
    |
 LL |     if let ...true = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:116:15
+  --> $DIR/recover-range-pats.rs:128:15
    |
 LL |     if let ....3 = 0 {}
    |               ^^ help: must have an integer part: `0.3`
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:116:12
+  --> $DIR/recover-range-pats.rs:128:12
    |
 LL |     if let ....3 = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:137:17
+  --> $DIR/recover-range-pats.rs:150:17
    |
 LL |             let ...$e;
    |                 ^^^ help: use `..=` instead
@@ -170,7 +170,7 @@ LL |     mac!(0);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:141:19
+  --> $DIR/recover-range-pats.rs:154:19
    |
 LL |             let $e...;
    |                   ^^^ help: use `..` instead
@@ -182,7 +182,7 @@ LL |     mac!(0);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:142:19
+  --> $DIR/recover-range-pats.rs:155:19
    |
 LL |             let $e..=;
    |                   ^^^ help: use `..` instead
@@ -204,51 +204,74 @@ note: the lint level is defined here
    |
 LL | #![deny(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:43:13
+  --> $DIR/recover-range-pats.rs:45:13
    |
 LL |     if let 0...Y = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:44:13
+  --> $DIR/recover-range-pats.rs:48:13
    |
 LL |     if let X...3 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:45:13
+  --> $DIR/recover-range-pats.rs:51:13
    |
 LL |     if let X...Y = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:46:16
+  --> $DIR/recover-range-pats.rs:54:16
    |
 LL |     if let true...Y = 0 {}
    |                ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:48:13
+  --> $DIR/recover-range-pats.rs:57:13
    |
 LL |     if let X...true = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:50:14
+  --> $DIR/recover-range-pats.rs:60:14
    |
 LL |     if let .0...Y = 0 {}
    |              ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:53:13
+  --> $DIR/recover-range-pats.rs:64:13
    |
 LL |     if let X... .0 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:126:20
+  --> $DIR/recover-range-pats.rs:138:20
    |
 LL |             let $e1...$e2;
    |                    ^^^ help: use `..=` for an inclusive range
@@ -256,6 +279,8 @@ LL |             let $e1...$e2;
 LL |     mac2!(0, 1);
    |     ------------ in this macro invocation
    |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
@@ -325,7 +350,7 @@ LL |     if let X..=.0 = 0 {}
    |            this is of type `u8`
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:46:12
+  --> $DIR/recover-range-pats.rs:54:12
    |
 LL |     if let true...Y = 0 {}
    |            ^^^^   - this is of type `u8`
@@ -333,7 +358,7 @@ LL |     if let true...Y = 0 {}
    |            this is of type `bool` but it should be `char` or numeric
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:48:16
+  --> $DIR/recover-range-pats.rs:57:16
    |
 LL |     if let X...true = 0 {}
    |            -   ^^^^ this is of type `bool` but it should be `char` or numeric
@@ -341,7 +366,7 @@ LL |     if let X...true = 0 {}
    |            this is of type `u8`
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:50:12
+  --> $DIR/recover-range-pats.rs:60:12
    |
 LL |     if let .0...Y = 0 {}
    |            ^^   - this is of type `u8`
@@ -349,7 +374,7 @@ LL |     if let .0...Y = 0 {}
    |            expected integer, found floating-point number
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:53:17
+  --> $DIR/recover-range-pats.rs:64:17
    |
 LL |     if let X... .0 = 0 {}
    |            -    ^^   - this expression has type `u8`
@@ -358,73 +383,73 @@ LL |     if let X... .0 = 0 {}
    |            this is of type `u8`
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:61:12
+  --> $DIR/recover-range-pats.rs:73:12
    |
 LL |     if let true.. = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:63:12
+  --> $DIR/recover-range-pats.rs:75:12
    |
 LL |     if let .0.. = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:71:12
+  --> $DIR/recover-range-pats.rs:83:12
    |
 LL |     if let true..= = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:73:12
+  --> $DIR/recover-range-pats.rs:85:12
    |
 LL |     if let .0..= = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:81:12
+  --> $DIR/recover-range-pats.rs:93:12
    |
 LL |     if let true... = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:83:12
+  --> $DIR/recover-range-pats.rs:95:12
    |
 LL |     if let .0... = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:91:14
+  --> $DIR/recover-range-pats.rs:103:14
    |
 LL |     if let ..true = 0 {}
    |              ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:93:15
+  --> $DIR/recover-range-pats.rs:105:15
    |
 LL |     if let .. .0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:101:15
+  --> $DIR/recover-range-pats.rs:113:15
    |
 LL |     if let ..=true = 0 {}
    |               ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:103:15
+  --> $DIR/recover-range-pats.rs:115:15
    |
 LL |     if let ..=.0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:113:15
+  --> $DIR/recover-range-pats.rs:125:15
    |
 LL |     if let ...true = 0 {}
    |               ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:116:15
+  --> $DIR/recover-range-pats.rs:128:15
    |
 LL |     if let ....3 = 0 {}
    |               ^^ expected integer, found floating-point number
diff --git a/src/test/ui/parser/stmt_expr_attrs_placement.rs b/src/test/ui/parser/stmt_expr_attrs_placement.rs
index b8a794f4b92..d488cd0c2d3 100644
--- a/src/test/ui/parser/stmt_expr_attrs_placement.rs
+++ b/src/test/ui/parser/stmt_expr_attrs_placement.rs
@@ -8,15 +8,31 @@ fn main() {
     //~^ ERROR an inner attribute is not permitted in this context
 
     let b = (#![allow(warnings)] 1, 2);
+    //~^ ERROR an inner attribute is not permitted in this context
 
     let c = {
         #![allow(warnings)]
         (#![allow(warnings)] 1, 2)
+        //~^ ERROR an inner attribute is not permitted in this context
     };
 
     let d = {
         #![allow(warnings)]
         let e = (#![allow(warnings)] 1, 2);
+        //~^ ERROR an inner attribute is not permitted in this context
         e
     };
+
+    let e = [#![allow(warnings)] 1, 2];
+    //~^ ERROR an inner attribute is not permitted in this context
+
+    let f = [#![allow(warnings)] 1; 0];
+    //~^ ERROR an inner attribute is not permitted in this context
+
+    let g = match true { #![allow(warnings)] _ => {} };
+    //~^ ERROR an inner attribute is not permitted in this context
+
+    struct MyStruct { field: u8 }
+    let h = MyStruct { #![allow(warnings)] field: 0 };
+    //~^ ERROR an inner attribute is not permitted in this context
 }
diff --git a/src/test/ui/parser/stmt_expr_attrs_placement.stderr b/src/test/ui/parser/stmt_expr_attrs_placement.stderr
index 1886a0f9ba0..185cc009640 100644
--- a/src/test/ui/parser/stmt_expr_attrs_placement.stderr
+++ b/src/test/ui/parser/stmt_expr_attrs_placement.stderr
@@ -6,5 +6,61 @@ LL |     let a = #![allow(warnings)] (1, 2);
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
-error: aborting due to previous error
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:10:14
+   |
+LL |     let b = (#![allow(warnings)] 1, 2);
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:15:10
+   |
+LL |         (#![allow(warnings)] 1, 2)
+   |          ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:21:18
+   |
+LL |         let e = (#![allow(warnings)] 1, 2);
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:26:14
+   |
+LL |     let e = [#![allow(warnings)] 1, 2];
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:29:14
+   |
+LL |     let f = [#![allow(warnings)] 1; 0];
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:32:26
+   |
+LL |     let g = match true { #![allow(warnings)] _ => {} };
+   |                          ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:36:24
+   |
+LL |     let h = MyStruct { #![allow(warnings)] field: 0 };
+   |                        ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/parser/trait-object-delimiters.rs b/src/test/ui/parser/trait-object-delimiters.rs
new file mode 100644
index 00000000000..650ab572261
--- /dev/null
+++ b/src/test/ui/parser/trait-object-delimiters.rs
@@ -0,0 +1,17 @@
+// edition:2018
+
+fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+
+fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
+
+fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
+//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
+//~| ERROR at least one trait is required for an object type
+
+fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
+
+fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} //~ ERROR invalid `dyn` keyword
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+
+fn main() {}
diff --git a/src/test/ui/parser/trait-object-delimiters.stderr b/src/test/ui/parser/trait-object-delimiters.stderr
new file mode 100644
index 00000000000..18b1b24122e
--- /dev/null
+++ b/src/test/ui/parser/trait-object-delimiters.stderr
@@ -0,0 +1,77 @@
+error: ambiguous `+` in a type
+  --> $DIR/trait-object-delimiters.rs:3:13
+   |
+LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef<str>)`
+
+error: incorrect braces around trait bounds
+  --> $DIR/trait-object-delimiters.rs:6:17
+   |
+LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {}
+   |                 ^                 ^
+   |
+help: remove the parentheses
+   |
+LL | fn foo2(_: &dyn Drop + AsRef<str>) {}
+   |                --               --
+
+error: expected parameter name, found `{`
+  --> $DIR/trait-object-delimiters.rs:8:17
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |                 ^ expected parameter name
+
+error: expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
+  --> $DIR/trait-object-delimiters.rs:8:17
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |                -^ expected one of 8 possible tokens
+   |                |
+   |                help: missing `,`
+
+error: expected identifier, found `<`
+  --> $DIR/trait-object-delimiters.rs:12:17
+   |
+LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {}
+   |                 ^ expected identifier
+
+error: invalid `dyn` keyword
+  --> $DIR/trait-object-delimiters.rs:14:25
+   |
+LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
+   |                         ^^^ help: remove this keyword
+   |
+   = help: `dyn` is only needed at the start of a trait `+`-separated list
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-object-delimiters.rs:3:24
+   |
+LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
+   |                 ----   ^^^^^^^^^^ additional non-auto trait
+   |                 |
+   |                 first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0224]: at least one trait is required for an object type
+  --> $DIR/trait-object-delimiters.rs:8:13
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |             ^^^
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-object-delimiters.rs:14:29
+   |
+LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
+   |                  ----       ^^^^^^^^^^ additional non-auto trait
+   |                  |
+   |                  first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0224, E0225.
+For more information about an error, try `rustc --explain E0224`.
diff --git a/src/test/ui/parser/trait-object-trait-parens.rs b/src/test/ui/parser/trait-object-trait-parens.rs
index 9fbc938c4dc..7d55da7d097 100644
--- a/src/test/ui/parser/trait-object-trait-parens.rs
+++ b/src/test/ui/parser/trait-object-trait-parens.rs
@@ -9,12 +9,15 @@ fn main() {
     //~^ ERROR `?Trait` is not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
-    let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
+    //~| WARN this was previously accepted by the compiler
+    let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
     //~^ ERROR `?Trait` is not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
-    let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
+    //~| WARN this was previously accepted by the compiler
+    let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
     //~^ ERROR `?Trait` is not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr
index 6efbfad8f38..79b6892dc07 100644
--- a/src/test/ui/parser/trait-object-trait-parens.stderr
+++ b/src/test/ui/parser/trait-object-trait-parens.stderr
@@ -5,16 +5,16 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    |                        ^^^^^^^^
 
 error: `?Trait` is not permitted in trait object types
-  --> $DIR/trait-object-trait-parens.rs:12:17
+  --> $DIR/trait-object-trait-parens.rs:13:16
    |
-LL |     let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
-   |                 ^^^^^^
+LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+   |                ^^^^^^
 
 error: `?Trait` is not permitted in trait object types
-  --> $DIR/trait-object-trait-parens.rs:16:46
+  --> $DIR/trait-object-trait-parens.rs:18:44
    |
-LL |     let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
-   |                                              ^^^^^^^^
+LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+   |                                            ^^^^^^^^
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/trait-object-trait-parens.rs:8:16
@@ -23,18 +23,26 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/trait-object-trait-parens.rs:12:16
+  --> $DIR/trait-object-trait-parens.rs:13:16
    |
-LL |     let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Obj)`
+LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn ?Sized + (for<'a> Trait<'a>) + (Obj)`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/trait-object-trait-parens.rs:16:16
+  --> $DIR/trait-object-trait-parens.rs:18:16
+   |
+LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn for<'a> Trait<'a> + (Obj) + (?Sized)`
    |
-LL |     let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Obj) + (?Sized)`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/trait-object-trait-parens.rs:8:35
@@ -48,23 +56,23 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/trait-object-trait-parens.rs:12:49
+  --> $DIR/trait-object-trait-parens.rs:13:47
    |
-LL |     let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
-   |                           -------------------   ^^^^^ additional non-auto trait
-   |                           |
-   |                           first non-auto trait
+LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+   |                         -------------------   ^^^^^ additional non-auto trait
+   |                         |
+   |                         first non-auto trait
    |
    = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/trait-object-trait-parens.rs:16:38
+  --> $DIR/trait-object-trait-parens.rs:18:36
    |
-LL |     let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
-   |                 -----------------    ^^^^^ additional non-auto trait
-   |                 |
-   |                 first non-auto trait
+LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+   |                -----------------   ^^^^^ additional non-auto trait
+   |                |
+   |                first non-auto trait
    |
    = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
diff --git a/src/test/ui/parser/unsafe-mod.stderr b/src/test/ui/parser/unsafe-mod.stderr
index 259b2c1d61e..dac6e7a3550 100644
--- a/src/test/ui/parser/unsafe-mod.stderr
+++ b/src/test/ui/parser/unsafe-mod.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `n`
 LL | unsafe mod n;
    | ^^^^^^^^^^^^^
    |
-   = help: to create the module `n`, create file "$DIR/n.rs"
+   = help: to create the module `n`, create file "$DIR/n.rs" or "$DIR/n/mod.rs"
 
 error: module cannot be declared unsafe
   --> $DIR/unsafe-mod.rs:1:1
diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr
index 497c93b2949..44d6a854b3d 100644
--- a/src/test/ui/pattern/pattern-error-continue.stderr
+++ b/src/test/ui/pattern/pattern-error-continue.stderr
@@ -9,11 +9,21 @@ error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D`
    |
 LL |     B(isize, isize),
    |     --------------- similarly named tuple variant `B` defined here
+LL |     C(isize, isize, isize),
+LL |     D
+   |     - `A::D` defined here
 ...
 LL |         A::D(_) => (),
-   |         ^^^-
-   |            |
-   |            help: a tuple variant with a similar name exists: `B`
+   |         ^^^^^^^
+   |
+help: use this syntax instead
+   |
+LL |         A::D => (),
+   |         ^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         A::B(_) => (),
+   |            ^
 
 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
   --> $DIR/pattern-error-continue.rs:17:9
diff --git a/src/test/ui/proc-macro/inner-attrs.rs b/src/test/ui/proc-macro/inner-attrs.rs
index 14ec57ad626..2e3c704da43 100644
--- a/src/test/ui/proc-macro/inner-attrs.rs
+++ b/src/test/ui/proc-macro/inner-attrs.rs
@@ -1,6 +1,7 @@
 // compile-flags: -Z span-debug --error-format human
 // aux-build:test-macros.rs
 // edition:2018
+
 #![feature(custom_inner_attributes)]
 #![feature(proc_macro_hygiene)]
 #![feature(stmt_expr_attributes)]
@@ -34,8 +35,6 @@ struct MyStruct {
 struct MyDerivePrint {
     field: [u8; {
         match true {
-            #![cfg_attr(not(FALSE), rustc_dummy(first))]
-            #![cfg_attr(not(FALSE), rustc_dummy(second))]
             _ => {
                 #![cfg_attr(not(FALSE), rustc_dummy(third))]
                 true
@@ -46,49 +45,20 @@ struct MyDerivePrint {
 }
 
 fn bar() {
-    (#![print_target_and_args(fifth)] 1, 2);
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-
     #[print_target_and_args(tuple_attrs)] (
-        #![cfg_attr(FALSE, rustc_dummy)]
         3, 4, {
             #![cfg_attr(not(FALSE), rustc_dummy(innermost))]
             5
         }
     );
 
-    #[print_target_and_args(array_attrs)] [
-        #![rustc_dummy(inner)]
-        true; 0
-    ];
-
     #[print_target_and_args(tuple_attrs)] (
-        #![cfg_attr(FALSE, rustc_dummy)]
         3, 4, {
             #![cfg_attr(not(FALSE), rustc_dummy(innermost))]
             5
         }
     );
 
-    #[print_target_and_args(array_attrs)] [
-        #![rustc_dummy(inner)]
-        true; 0
-    ];
-
-    [#![print_target_and_args(sixth)] 1 , 2];
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-    [#![print_target_and_args(seventh)] true ; 5];
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-
-    match 0 {
-        #![print_target_and_args(eighth)]
-        //~^ ERROR expected non-macro inner attribute, found attribute macro
-        _ => {}
-    }
-
-    MyStruct { #![print_target_and_args(ninth)] field: true };
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-
     for _ in &[true] {
         #![print_attr] //~ ERROR expected non-macro inner attribute
     }
diff --git a/src/test/ui/proc-macro/inner-attrs.stderr b/src/test/ui/proc-macro/inner-attrs.stderr
index 7f22c5f30d6..4da8751ef7f 100644
--- a/src/test/ui/proc-macro/inner-attrs.stderr
+++ b/src/test/ui/proc-macro/inner-attrs.stderr
@@ -1,56 +1,26 @@
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:49:9
-   |
-LL |     (#![print_target_and_args(fifth)] 1, 2);
-   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:78:9
-   |
-LL |     [#![print_target_and_args(sixth)] 1 , 2];
-   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:80:9
-   |
-LL |     [#![print_target_and_args(seventh)] true ; 5];
-   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:84:12
-   |
-LL |         #![print_target_and_args(eighth)]
-   |            ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:89:19
-   |
-LL |     MyStruct { #![print_target_and_args(ninth)] field: true };
-   |                   ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:93:12
+  --> $DIR/inner-attrs.rs:63:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:97:12
+  --> $DIR/inner-attrs.rs:67:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:101:12
+  --> $DIR/inner-attrs.rs:71:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:105:12
+  --> $DIR/inner-attrs.rs:75:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
-error: aborting due to 9 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/proc-macro/inner-attrs.stdout b/src/test/ui/proc-macro/inner-attrs.stdout
index 2f442e83002..77f42370493 100644
--- a/src/test/ui/proc-macro/inner-attrs.stdout
+++ b/src/test/ui/proc-macro/inner-attrs.stdout
@@ -2,7 +2,7 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): first
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "first",
-        span: $DIR/inner-attrs.rs:15:25: 15:30 (#0),
+        span: $DIR/inner-attrs.rs:16:25: 16:30 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second)] fn foo()
@@ -11,40 +11,40 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:16:1: 16:2 (#0),
+        span: $DIR/inner-attrs.rs:17:1: 17:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/inner-attrs.rs:16:3: 16:24 (#0),
+                span: $DIR/inner-attrs.rs:17:3: 17:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "second",
-                        span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
+                        span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:16:24: 16:32 (#0),
+                span: $DIR/inner-attrs.rs:17:24: 17:32 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:16:2: 16:33 (#0),
+        span: $DIR/inner-attrs.rs:17:2: 17:33 (#0),
     },
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -52,72 +52,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
+                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
+                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
+                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+                                span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
+                        span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
+                span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): second
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "second",
-        span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
+        span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo()
@@ -125,16 +125,16 @@ PRINT-ATTR INPUT (DISPLAY): fn foo()
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -142,88 +142,88 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
+                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
+                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
+                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+                                span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
+                        span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
+                span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): third
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "third",
-        span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+        span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() { # ! [print_target_and_args(fourth)] }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -231,70 +231,70 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): fourth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fourth",
-        span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+        span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_first",
-        span: $DIR/inner-attrs.rs:22:25: 22:34 (#0),
+        span: $DIR/inner-attrs.rs:23:25: 23:34 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod
@@ -306,35 +306,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:23:1: 23:2 (#0),
+        span: $DIR/inner-attrs.rs:24:1: 24:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/inner-attrs.rs:23:3: 23:24 (#0),
+                span: $DIR/inner-attrs.rs:24:3: 24:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "mod_second",
-                        span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+                        span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:23:24: 23:36 (#0),
+                span: $DIR/inner-attrs.rs:24:24: 24:36 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:23:2: 23:37 (#0),
+        span: $DIR/inner-attrs.rs:24:2: 24:37 (#0),
     },
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -342,72 +342,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
+                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
+                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_third",
-                                span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+                                span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+                        span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+                span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_second",
-        span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+        span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod
@@ -418,11 +418,11 @@ PRINT-ATTR INPUT (DISPLAY): mod inline_mod
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -430,83 +430,83 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
+                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
+                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_third",
-                                span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+                                span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+                        span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+                span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_third",
-        span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+        span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod { # ! [print_target_and_args(mod_fourth)] }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -514,192 +514,125 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_fourth",
-        span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+        span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint
 {
     field :
-    [u8 ;
-     {
-         match true
-         {
-             # ! [rustc_dummy(first)] # ! [rustc_dummy(second)] _ =>
-             { # ! [rustc_dummy(third)] true }
-         } ; 0
-     }]
+    [u8 ; { match true { _ => { # ! [rustc_dummy(third)] true } } ; 0 }]
 }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/inner-attrs.rs:34:1: 34:7 (#0),
+        span: $DIR/inner-attrs.rs:35:1: 35:7 (#0),
     },
     Ident {
         ident: "MyDerivePrint",
-        span: $DIR/inner-attrs.rs:34:8: 34:21 (#0),
+        span: $DIR/inner-attrs.rs:35:8: 35:21 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "field",
-                span: $DIR/inner-attrs.rs:35:5: 35:10 (#0),
+                span: $DIR/inner-attrs.rs:36:5: 36:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:35:10: 35:11 (#0),
+                span: $DIR/inner-attrs.rs:36:10: 36:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/inner-attrs.rs:35:13: 35:15 (#0),
+                        span: $DIR/inner-attrs.rs:36:13: 36:15 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:35:15: 35:16 (#0),
+                        span: $DIR/inner-attrs.rs:36:15: 36:16 (#0),
                     },
                     Group {
                         delimiter: Brace,
                         stream: TokenStream [
                             Ident {
                                 ident: "match",
-                                span: $DIR/inner-attrs.rs:36:9: 36:14 (#0),
+                                span: $DIR/inner-attrs.rs:37:9: 37:14 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/inner-attrs.rs:36:15: 36:19 (#0),
+                                span: $DIR/inner-attrs.rs:37:15: 37:19 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
-                                    Punct {
-                                        ch: '#',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
-                                    },
-                                    Punct {
-                                        ch: '!',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:37:14: 37:15 (#0),
-                                    },
-                                    Group {
-                                        delimiter: Bracket,
-                                        stream: TokenStream [
-                                            Ident {
-                                                ident: "rustc_dummy",
-                                                span: $DIR/inner-attrs.rs:37:37: 37:48 (#0),
-                                            },
-                                            Group {
-                                                delimiter: Parenthesis,
-                                                stream: TokenStream [
-                                                    Ident {
-                                                        ident: "first",
-                                                        span: $DIR/inner-attrs.rs:37:49: 37:54 (#0),
-                                                    },
-                                                ],
-                                                span: $DIR/inner-attrs.rs:37:48: 37:55 (#0),
-                                            },
-                                        ],
-                                        span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
-                                    },
-                                    Punct {
-                                        ch: '#',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
-                                    },
-                                    Punct {
-                                        ch: '!',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:38:14: 38:15 (#0),
-                                    },
-                                    Group {
-                                        delimiter: Bracket,
-                                        stream: TokenStream [
-                                            Ident {
-                                                ident: "rustc_dummy",
-                                                span: $DIR/inner-attrs.rs:38:37: 38:48 (#0),
-                                            },
-                                            Group {
-                                                delimiter: Parenthesis,
-                                                stream: TokenStream [
-                                                    Ident {
-                                                        ident: "second",
-                                                        span: $DIR/inner-attrs.rs:38:49: 38:55 (#0),
-                                                    },
-                                                ],
-                                                span: $DIR/inner-attrs.rs:38:48: 38:56 (#0),
-                                            },
-                                        ],
-                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
-                                    },
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/inner-attrs.rs:39:13: 39:14 (#0),
+                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+                                        span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+                                        span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
@@ -707,69 +640,69 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+                                                span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
                                             },
                                             Punct {
                                                 ch: '!',
                                                 spacing: Alone,
-                                                span: $DIR/inner-attrs.rs:40:18: 40:19 (#0),
+                                                span: $DIR/inner-attrs.rs:39:18: 39:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "rustc_dummy",
-                                                        span: $DIR/inner-attrs.rs:40:41: 40:52 (#0),
+                                                        span: $DIR/inner-attrs.rs:39:41: 39:52 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "third",
-                                                                span: $DIR/inner-attrs.rs:40:53: 40:58 (#0),
+                                                                span: $DIR/inner-attrs.rs:39:53: 39:58 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/inner-attrs.rs:40:52: 40:59 (#0),
+                                                        span: $DIR/inner-attrs.rs:39:52: 39:59 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+                                                span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
                                             },
                                             Ident {
                                                 ident: "true",
-                                                span: $DIR/inner-attrs.rs:41:17: 41:21 (#0),
+                                                span: $DIR/inner-attrs.rs:40:17: 40:21 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:39:18: 42:14 (#0),
+                                        span: $DIR/inner-attrs.rs:38:18: 41:14 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:36:20: 43:10 (#0),
+                                span: $DIR/inner-attrs.rs:37:20: 42:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/inner-attrs.rs:43:10: 43:11 (#0),
+                                span: $DIR/inner-attrs.rs:42:10: 42:11 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/inner-attrs.rs:44:9: 44:10 (#0),
+                                span: $DIR/inner-attrs.rs:43:9: 43:10 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:35:17: 45:6 (#0),
+                        span: $DIR/inner-attrs.rs:36:17: 44:6 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:35:12: 45:7 (#0),
+                span: $DIR/inner-attrs.rs:36:12: 44:7 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:34:22: 46:2 (#0),
+        span: $DIR/inner-attrs.rs:35:22: 45:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tuple_attrs",
-        span: $DIR/inner-attrs.rs:52:29: 52:40 (#0),
+        span: $DIR/inner-attrs.rs:48:29: 48:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
@@ -781,23 +714,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:54:9: 54:10 (#0),
+                span: $DIR/inner-attrs.rs:49:9: 49:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:54:10: 54:11 (#0),
+                span: $DIR/inner-attrs.rs:49:10: 49:11 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:54:12: 54:13 (#0),
+                span: $DIR/inner-attrs.rs:49:12: 49:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:54:13: 54:14 (#0),
+                span: $DIR/inner-attrs.rs:49:13: 49:14 (#0),
             },
             Group {
                 delimiter: Brace,
@@ -805,151 +738,85 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                     Punct {
                         ch: '#',
                         spacing: Joint,
-                        span: $DIR/inner-attrs.rs:55:13: 55:14 (#0),
+                        span: $DIR/inner-attrs.rs:50:13: 50:14 (#0),
                     },
                     Punct {
                         ch: '!',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:55:14: 55:15 (#0),
+                        span: $DIR/inner-attrs.rs:50:14: 50:15 (#0),
                     },
                     Group {
                         delimiter: Bracket,
                         stream: TokenStream [
                             Ident {
                                 ident: "cfg_attr",
-                                span: $DIR/inner-attrs.rs:55:16: 55:24 (#0),
+                                span: $DIR/inner-attrs.rs:50:16: 50:24 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "not",
-                                        span: $DIR/inner-attrs.rs:55:25: 55:28 (#0),
+                                        span: $DIR/inner-attrs.rs:50:25: 50:28 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/inner-attrs.rs:55:29: 55:34 (#0),
+                                                span: $DIR/inner-attrs.rs:50:29: 50:34 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:55:28: 55:35 (#0),
+                                        span: $DIR/inner-attrs.rs:50:28: 50:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:55:35: 55:36 (#0),
+                                        span: $DIR/inner-attrs.rs:50:35: 50:36 (#0),
                                     },
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/inner-attrs.rs:55:37: 55:48 (#0),
+                                        span: $DIR/inner-attrs.rs:50:37: 50:48 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "innermost",
-                                                span: $DIR/inner-attrs.rs:55:49: 55:58 (#0),
+                                                span: $DIR/inner-attrs.rs:50:49: 50:58 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:55:48: 55:59 (#0),
+                                        span: $DIR/inner-attrs.rs:50:48: 50:59 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:55:24: 55:60 (#0),
+                                span: $DIR/inner-attrs.rs:50:24: 50:60 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:55:15: 55:61 (#0),
+                        span: $DIR/inner-attrs.rs:50:15: 50:61 (#0),
                     },
                     Literal {
                         kind: Integer,
                         symbol: "5",
                         suffix: None,
-                        span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
+                        span: $DIR/inner-attrs.rs:51:13: 51:14 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:54:15: 57:10 (#0),
+                span: $DIR/inner-attrs.rs:49:15: 52:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:52:43: 58:6 (#0),
+        span: $DIR/inner-attrs.rs:48:43: 53:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:58:6: 58:7 (#0),
-    },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "array_attrs",
-        span: $DIR/inner-attrs.rs:60:29: 60:40 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Punct {
-                ch: '#',
-                spacing: Joint,
-                span: $DIR/inner-attrs.rs:61:9: 61:10 (#0),
-            },
-            Punct {
-                ch: '!',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:61:10: 61:11 (#0),
-            },
-            Group {
-                delimiter: Bracket,
-                stream: TokenStream [
-                    Ident {
-                        ident: "rustc_dummy",
-                        span: $DIR/inner-attrs.rs:61:12: 61:23 (#0),
-                    },
-                    Group {
-                        delimiter: Parenthesis,
-                        stream: TokenStream [
-                            Ident {
-                                ident: "inner",
-                                span: $DIR/inner-attrs.rs:61:24: 61:29 (#0),
-                            },
-                        ],
-                        span: $DIR/inner-attrs.rs:61:23: 61:30 (#0),
-                    },
-                ],
-                span: $DIR/inner-attrs.rs:61:11: 61:31 (#0),
-            },
-            Ident {
-                ident: "true",
-                span: $DIR/inner-attrs.rs:62:9: 62:13 (#0),
-            },
-            Punct {
-                ch: ';',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:62:13: 62:14 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "0",
-                suffix: None,
-                span: $DIR/inner-attrs.rs:62:15: 62:16 (#0),
-            },
-        ],
-        span: $DIR/inner-attrs.rs:60:43: 63:6 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/inner-attrs.rs:63:6: 63:7 (#0),
+        span: $DIR/inner-attrs.rs:53:6: 53:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tuple_attrs",
-        span: $DIR/inner-attrs.rs:65:29: 65:40 (#0),
+        span: $DIR/inner-attrs.rs:55:29: 55:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
@@ -961,23 +828,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:67:9: 67:10 (#0),
+                span: $DIR/inner-attrs.rs:56:9: 56:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:67:10: 67:11 (#0),
+                span: $DIR/inner-attrs.rs:56:10: 56:11 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:67:12: 67:13 (#0),
+                span: $DIR/inner-attrs.rs:56:12: 56:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:67:13: 67:14 (#0),
+                span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
             },
             Group {
                 delimiter: Brace,
@@ -985,171 +852,105 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                     Punct {
                         ch: '#',
                         spacing: Joint,
-                        span: $DIR/inner-attrs.rs:68:13: 68:14 (#0),
+                        span: $DIR/inner-attrs.rs:57:13: 57:14 (#0),
                     },
                     Punct {
                         ch: '!',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:68:14: 68:15 (#0),
+                        span: $DIR/inner-attrs.rs:57:14: 57:15 (#0),
                     },
                     Group {
                         delimiter: Bracket,
                         stream: TokenStream [
                             Ident {
                                 ident: "cfg_attr",
-                                span: $DIR/inner-attrs.rs:68:16: 68:24 (#0),
+                                span: $DIR/inner-attrs.rs:57:16: 57:24 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "not",
-                                        span: $DIR/inner-attrs.rs:68:25: 68:28 (#0),
+                                        span: $DIR/inner-attrs.rs:57:25: 57:28 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/inner-attrs.rs:68:29: 68:34 (#0),
+                                                span: $DIR/inner-attrs.rs:57:29: 57:34 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:68:28: 68:35 (#0),
+                                        span: $DIR/inner-attrs.rs:57:28: 57:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:68:35: 68:36 (#0),
+                                        span: $DIR/inner-attrs.rs:57:35: 57:36 (#0),
                                     },
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/inner-attrs.rs:68:37: 68:48 (#0),
+                                        span: $DIR/inner-attrs.rs:57:37: 57:48 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "innermost",
-                                                span: $DIR/inner-attrs.rs:68:49: 68:58 (#0),
+                                                span: $DIR/inner-attrs.rs:57:49: 57:58 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:68:48: 68:59 (#0),
+                                        span: $DIR/inner-attrs.rs:57:48: 57:59 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:68:24: 68:60 (#0),
+                                span: $DIR/inner-attrs.rs:57:24: 57:60 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:68:15: 68:61 (#0),
+                        span: $DIR/inner-attrs.rs:57:15: 57:61 (#0),
                     },
                     Literal {
                         kind: Integer,
                         symbol: "5",
                         suffix: None,
-                        span: $DIR/inner-attrs.rs:69:13: 69:14 (#0),
-                    },
-                ],
-                span: $DIR/inner-attrs.rs:67:15: 70:10 (#0),
-            },
-        ],
-        span: $DIR/inner-attrs.rs:65:43: 71:6 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/inner-attrs.rs:71:6: 71:7 (#0),
-    },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "array_attrs",
-        span: $DIR/inner-attrs.rs:73:29: 73:40 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Punct {
-                ch: '#',
-                spacing: Joint,
-                span: $DIR/inner-attrs.rs:74:9: 74:10 (#0),
-            },
-            Punct {
-                ch: '!',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:74:10: 74:11 (#0),
-            },
-            Group {
-                delimiter: Bracket,
-                stream: TokenStream [
-                    Ident {
-                        ident: "rustc_dummy",
-                        span: $DIR/inner-attrs.rs:74:12: 74:23 (#0),
-                    },
-                    Group {
-                        delimiter: Parenthesis,
-                        stream: TokenStream [
-                            Ident {
-                                ident: "inner",
-                                span: $DIR/inner-attrs.rs:74:24: 74:29 (#0),
-                            },
-                        ],
-                        span: $DIR/inner-attrs.rs:74:23: 74:30 (#0),
+                        span: $DIR/inner-attrs.rs:58:13: 58:14 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:74:11: 74:31 (#0),
-            },
-            Ident {
-                ident: "true",
-                span: $DIR/inner-attrs.rs:75:9: 75:13 (#0),
-            },
-            Punct {
-                ch: ';',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:75:13: 75:14 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "0",
-                suffix: None,
-                span: $DIR/inner-attrs.rs:75:15: 75:16 (#0),
+                span: $DIR/inner-attrs.rs:56:15: 59:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:73:43: 76:6 (#0),
+        span: $DIR/inner-attrs.rs:55:43: 60:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:76:6: 76:7 (#0),
+        span: $DIR/inner-attrs.rs:60:6: 60:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tenth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tenth",
-        span: $DIR/inner-attrs.rs:112:42: 112:47 (#0),
+        span: $DIR/inner-attrs.rs:82:42: 82:47 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:111:5: 111:7 (#0),
+        span: $DIR/inner-attrs.rs:81:5: 81:7 (#0),
     },
     Ident {
         ident: "weird_extern",
-        span: $DIR/inner-attrs.rs:111:8: 111:20 (#0),
+        span: $DIR/inner-attrs.rs:81:8: 81:20 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:111:20: 111:22 (#0),
+        span: $DIR/inner-attrs.rs:81:20: 81:22 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:111:23: 113:6 (#0),
+        span: $DIR/inner-attrs.rs:81:23: 83:6 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/simple-tuple.rs b/src/test/ui/proc-macro/simple-tuple.rs
deleted file mode 100644
index c94c5877e22..00000000000
--- a/src/test/ui/proc-macro/simple-tuple.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// check-pass
-// compile-flags: -Z span-debug --error-format human
-// aux-build:test-macros.rs
-// edition:2018
-
-#![feature(proc_macro_hygiene)]
-
-#![no_std] // Don't load unnecessary hygiene information from std
-extern crate std;
-
-#[macro_use]
-extern crate test_macros;
-
-fn main() {
-    #[print_target_and_args(my_arg)] (
-        #![cfg_attr(not(FALSE), allow(unused))]
-        1, 2, 3
-    );
-}
diff --git a/src/test/ui/proc-macro/simple-tuple.stdout b/src/test/ui/proc-macro/simple-tuple.stdout
deleted file mode 100644
index 1cc8579a467..00000000000
--- a/src/test/ui/proc-macro/simple-tuple.stdout
+++ /dev/null
@@ -1,79 +0,0 @@
-PRINT-ATTR_ARGS INPUT (DISPLAY): my_arg
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "my_arg",
-        span: $DIR/simple-tuple.rs:15:29: 15:35 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): (# ! [allow(unused)] 1, 2, 3) ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Group {
-        delimiter: Parenthesis,
-        stream: TokenStream [
-            Punct {
-                ch: '#',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
-            },
-            Punct {
-                ch: '!',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:16:10: 16:11 (#0),
-            },
-            Group {
-                delimiter: Bracket,
-                stream: TokenStream [
-                    Ident {
-                        ident: "allow",
-                        span: $DIR/simple-tuple.rs:16:33: 16:38 (#0),
-                    },
-                    Group {
-                        delimiter: Parenthesis,
-                        stream: TokenStream [
-                            Ident {
-                                ident: "unused",
-                                span: $DIR/simple-tuple.rs:16:39: 16:45 (#0),
-                            },
-                        ],
-                        span: $DIR/simple-tuple.rs:16:38: 16:46 (#0),
-                    },
-                ],
-                span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "1",
-                suffix: None,
-                span: $DIR/simple-tuple.rs:17:9: 17:10 (#0),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:17:10: 17:11 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "2",
-                suffix: None,
-                span: $DIR/simple-tuple.rs:17:12: 17:13 (#0),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:17:13: 17:14 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "3",
-                suffix: None,
-                span: $DIR/simple-tuple.rs:17:15: 17:16 (#0),
-            },
-        ],
-        span: $DIR/simple-tuple.rs:15:38: 18:6 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/simple-tuple.rs:18:6: 18:7 (#0),
-    },
-]
diff --git a/src/test/ui/range/exclusive-range-patterns-2021.rs b/src/test/ui/range/exclusive-range-patterns-2021.rs
new file mode 100644
index 00000000000..de69c9bf2f3
--- /dev/null
+++ b/src/test/ui/range/exclusive-range-patterns-2021.rs
@@ -0,0 +1,14 @@
+// edition:2021
+
+fn main() {
+    let n = 2;
+    match n {
+        0...3 => {}
+        //~^ ERROR `...` range patterns are deprecated
+        4...10 => {}
+        //~^ ERROR `...` range patterns are deprecated
+        (11...100) => {}
+        //~^ ERROR `...` range patterns are deprecated
+        _ => {}
+    }
+}
diff --git a/src/test/ui/range/exclusive-range-patterns-2021.stderr b/src/test/ui/range/exclusive-range-patterns-2021.stderr
new file mode 100644
index 00000000000..a967437041a
--- /dev/null
+++ b/src/test/ui/range/exclusive-range-patterns-2021.stderr
@@ -0,0 +1,27 @@
+error[E0783]: `...` range patterns are deprecated
+  --> $DIR/exclusive-range-patterns-2021.rs:6:9
+   |
+LL |         0...3 => {}
+   |         ^---^
+   |          |
+   |          help: use `..=` for an inclusive range
+
+error[E0783]: `...` range patterns are deprecated
+  --> $DIR/exclusive-range-patterns-2021.rs:8:9
+   |
+LL |         4...10 => {}
+   |         ^---^^
+   |          |
+   |          help: use `..=` for an inclusive range
+
+error[E0783]: `...` range patterns are deprecated
+  --> $DIR/exclusive-range-patterns-2021.rs:10:10
+   |
+LL |         (11...100) => {}
+   |          ^^---^^^
+   |            |
+   |            help: use `..=` for an inclusive range
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0783`.
diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.fixed b/src/test/ui/range/range-inclusive-pattern-precedence.fixed
index 22ab6c755be..6c012099676 100644
--- a/src/test/ui/range/range-inclusive-pattern-precedence.fixed
+++ b/src/test/ui/range/range-inclusive-pattern-precedence.fixed
@@ -10,10 +10,11 @@ pub fn main() {
     match &12 {
         &(0..=9) => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         //~| HELP use `..=` for an inclusive range
         &(10 ..=15) => {}
         //~^ ERROR the range pattern here has ambiguous interpretation
-        //~^^ HELP add parentheses to clarify the precedence
+        //~| HELP add parentheses to clarify the precedence
         &(16..=20) => {}
         _ => {}
     }
diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.rs b/src/test/ui/range/range-inclusive-pattern-precedence.rs
index f38a7920c94..ce763ba2677 100644
--- a/src/test/ui/range/range-inclusive-pattern-precedence.rs
+++ b/src/test/ui/range/range-inclusive-pattern-precedence.rs
@@ -10,10 +10,11 @@ pub fn main() {
     match &12 {
         &0...9 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         //~| HELP use `..=` for an inclusive range
         &10..=15 => {}
         //~^ ERROR the range pattern here has ambiguous interpretation
-        //~^^ HELP add parentheses to clarify the precedence
+        //~| HELP add parentheses to clarify the precedence
         &(16..=20) => {}
         _ => {}
     }
diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.stderr b/src/test/ui/range/range-inclusive-pattern-precedence.stderr
index 853141969c2..ffb833535c2 100644
--- a/src/test/ui/range/range-inclusive-pattern-precedence.stderr
+++ b/src/test/ui/range/range-inclusive-pattern-precedence.stderr
@@ -1,5 +1,5 @@
 error: the range pattern here has ambiguous interpretation
-  --> $DIR/range-inclusive-pattern-precedence.rs:14:10
+  --> $DIR/range-inclusive-pattern-precedence.rs:15:10
    |
 LL |         &10..=15 => {}
    |          ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
@@ -15,6 +15,8 @@ note: the lint level is defined here
    |
 LL | #![warn(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/range/range-inclusive-pattern-precedence2.rs b/src/test/ui/range/range-inclusive-pattern-precedence2.rs
index 6a3fd413e4f..7fa2698a496 100644
--- a/src/test/ui/range/range-inclusive-pattern-precedence2.rs
+++ b/src/test/ui/range/range-inclusive-pattern-precedence2.rs
@@ -9,6 +9,7 @@ fn main() {
         // FIXME: can we add suggestions like `&(0..=9)`?
         box 0...9 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         //~| HELP use `..=` for an inclusive range
         box 10..=15 => {}
         //~^ ERROR the range pattern here has ambiguous interpretation
diff --git a/src/test/ui/range/range-inclusive-pattern-precedence2.stderr b/src/test/ui/range/range-inclusive-pattern-precedence2.stderr
index 7fbd972569e..e8e62b485cc 100644
--- a/src/test/ui/range/range-inclusive-pattern-precedence2.stderr
+++ b/src/test/ui/range/range-inclusive-pattern-precedence2.stderr
@@ -1,5 +1,5 @@
 error: the range pattern here has ambiguous interpretation
-  --> $DIR/range-inclusive-pattern-precedence2.rs:13:13
+  --> $DIR/range-inclusive-pattern-precedence2.rs:14:13
    |
 LL |         box 10..=15 => {}
    |             ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
@@ -15,6 +15,8 @@ note: the lint level is defined here
    |
 LL | #![warn(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to previous error; 1 warning emitted
 
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-2457/mod_file_nonascii_forbidden.stderr b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
index e857a1e60e5..dd0dac95e36 100644
--- a/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
+++ b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `řųśť`
 LL | mod řųśť;
    | ^^^^^^^^^
    |
-   = help: to create the module `řųśť`, create file "$DIR/řųśť.rs"
+   = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" or "$DIR/řųśť/mod.rs"
 
 error[E0754]: trying to load file for module `řųśť` with non-ascii identifier name
   --> $DIR/mod_file_nonascii_forbidden.rs:1:5
diff --git a/src/test/ui/rust-2018/suggestions-not-always-applicable.fixed b/src/test/ui/rust-2018/suggestions-not-always-applicable.fixed
index 12348e6e07d..f5afbad9f78 100644
--- a/src/test/ui/rust-2018/suggestions-not-always-applicable.fixed
+++ b/src/test/ui/rust-2018/suggestions-not-always-applicable.fixed
@@ -14,12 +14,8 @@ pub struct Foo;
 mod test {
     use crate::foo::foo;
 
-    #[foo] //~ WARN: absolute paths must start with
-    //~| WARN: previously accepted
-    //~| WARN: absolute paths
-    //~| WARN: previously accepted
-    fn main() {
-    }
+    #[foo]
+    fn main() {}
 }
 
 fn main() {
diff --git a/src/test/ui/rust-2018/suggestions-not-always-applicable.rs b/src/test/ui/rust-2018/suggestions-not-always-applicable.rs
index 12348e6e07d..f5afbad9f78 100644
--- a/src/test/ui/rust-2018/suggestions-not-always-applicable.rs
+++ b/src/test/ui/rust-2018/suggestions-not-always-applicable.rs
@@ -14,12 +14,8 @@ pub struct Foo;
 mod test {
     use crate::foo::foo;
 
-    #[foo] //~ WARN: absolute paths must start with
-    //~| WARN: previously accepted
-    //~| WARN: absolute paths
-    //~| WARN: previously accepted
-    fn main() {
-    }
+    #[foo]
+    fn main() {}
 }
 
 fn main() {
diff --git a/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr b/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr
deleted file mode 100644
index 45502a5b880..00000000000
--- a/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr
+++ /dev/null
@@ -1,28 +0,0 @@
-warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/suggestions-not-always-applicable.rs:17:5
-   |
-LL |     #[foo]
-   |     ^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/suggestions-not-always-applicable.rs:8:9
-   |
-LL | #![warn(rust_2018_compatibility)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(absolute_paths_not_starting_with_crate)]` implied by `#[warn(rust_2018_compatibility)]`
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
-   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
-   = note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/suggestions-not-always-applicable.rs:17:5
-   |
-LL |     #[foo]
-   |     ^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
-   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
-   = note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 2 warnings emitted
-
diff --git a/src/test/ui/structs-enums/rec-align-u64.rs b/src/test/ui/structs-enums/rec-align-u64.rs
index 69544b1c060..cc6412e271a 100644
--- a/src/test/ui/structs-enums/rec-align-u64.rs
+++ b/src/test/ui/structs-enums/rec-align-u64.rs
@@ -35,6 +35,7 @@ struct Outer {
           target_os = "dragonfly",
           target_os = "emscripten",
           target_os = "freebsd",
+          target_os = "fuchsia",
           target_os = "linux",
           target_os = "macos",
           target_os = "netbsd",
diff --git a/src/test/ui/suggestions/import-trait-for-method-call.rs b/src/test/ui/suggestions/import-trait-for-method-call.rs
index 646f68dea14..4dbadbdf982 100644
--- a/src/test/ui/suggestions/import-trait-for-method-call.rs
+++ b/src/test/ui/suggestions/import-trait-for-method-call.rs
@@ -6,4 +6,11 @@ fn next_u64() -> u64 {
     h.finish() //~ ERROR no method named `finish` found for struct `DefaultHasher`
 }
 
-fn main() {}
+trait Bar {}
+impl Bar for String {}
+
+fn main() {
+    let s = String::from("hey");
+    let x: &dyn Bar = &s;
+    x.as_ref(); //~ ERROR the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds
+}
diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr
index f3ae20552f3..a2b9b9d14ab 100644
--- a/src/test/ui/suggestions/import-trait-for-method-call.stderr
+++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr
@@ -15,6 +15,22 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
 LL | use std::hash::Hasher;
    |
 
-error: aborting due to previous error
+error[E0599]: the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds were not satisfied
+  --> $DIR/import-trait-for-method-call.rs:15:7
+   |
+LL | trait Bar {}
+   | --------- doesn't satisfy `dyn Bar: AsRef<_>`
+...
+LL |     x.as_ref();
+   |       ^^^^^^ method cannot be called on `&dyn Bar` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `dyn Bar: AsRef<_>`
+           which is required by `&dyn Bar: AsRef<_>`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `as_ref`, perhaps you need to implement it:
+           candidate #1: `AsRef`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/issue-61963.rs b/src/test/ui/suggestions/issue-61963.rs
index 666fc965f02..b5c379ebc6e 100644
--- a/src/test/ui/suggestions/issue-61963.rs
+++ b/src/test/ui/suggestions/issue-61963.rs
@@ -11,15 +11,17 @@ extern crate issue_61963_1;
 // generate code which would trigger the lint.
 
 pub struct Baz;
-pub trait Bar { }
+pub trait Bar {}
 pub struct Qux<T>(T);
 
 #[dom_struct]
 pub struct Foo {
     //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this was previously accepted by the compiler
     qux: Qux<Qux<Baz>>,
     bar: Box<Bar>,
     //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this was previously accepted by the compiler
 }
 
 fn main() {}
diff --git a/src/test/ui/suggestions/issue-61963.stderr b/src/test/ui/suggestions/issue-61963.stderr
index 62ae5fa3fe5..f8c58b61734 100644
--- a/src/test/ui/suggestions/issue-61963.stderr
+++ b/src/test/ui/suggestions/issue-61963.stderr
@@ -1,5 +1,5 @@
 error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-61963.rs:21:14
+  --> $DIR/issue-61963.rs:22:14
    |
 LL |     bar: Box<Bar>,
    |              ^^^ help: use `dyn`: `dyn Bar`
@@ -9,12 +9,17 @@ note: the lint level is defined here
    |
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: trait objects without an explicit `dyn` are deprecated
   --> $DIR/issue-61963.rs:18:1
    |
 LL | pub struct Foo {
    | ^^^ help: use `dyn`: `dyn pub`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/issue-84700.rs b/src/test/ui/suggestions/issue-84700.rs
new file mode 100644
index 00000000000..a27169fdbb2
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84700.rs
@@ -0,0 +1,26 @@
+// test for suggestion on fieldless enum variant
+
+#[derive(PartialEq, Debug)]
+enum FarmAnimal {
+    Worm,
+    Cow,
+    Bull,
+    Chicken { num_eggs: usize },
+    Dog (String),
+}
+
+fn what_does_the_animal_say(animal: &FarmAnimal) {
+
+    let noise = match animal {
+        FarmAnimal::Cow(_) => "moo".to_string(),
+        //~^ ERROR expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow`
+        FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
+        //~^ ERROR expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
+        FarmAnimal::Dog{..} => "woof!".to_string(),
+        _ => todo!()
+    };
+
+    println!("{:?} says: {:?}", animal, noise);
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-84700.stderr b/src/test/ui/suggestions/issue-84700.stderr
new file mode 100644
index 00000000000..b36d8aba36d
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84700.stderr
@@ -0,0 +1,21 @@
+error[E0532]: expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow`
+  --> $DIR/issue-84700.rs:15:9
+   |
+LL |     Cow,
+   |     --- `FarmAnimal::Cow` defined here
+...
+LL |         FarmAnimal::Cow(_) => "moo".to_string(),
+   |         ^^^^^^^^^^^^^^^^^^ help: use this syntax instead: `FarmAnimal::Cow`
+
+error[E0532]: expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
+  --> $DIR/issue-84700.rs:17:9
+   |
+LL |     Chicken { num_eggs: usize },
+   |     --------------------------- `FarmAnimal::Chicken` defined here
+...
+LL |         FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FarmAnimal::Chicken { num_eggs }`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0532`.
diff --git a/src/test/ui/suggestions/unsized-function-parameter.fixed b/src/test/ui/suggestions/unsized-function-parameter.fixed
new file mode 100644
index 00000000000..18e93cb96cd
--- /dev/null
+++ b/src/test/ui/suggestions/unsized-function-parameter.fixed
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
+fn foo1(bar: &str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo2(_bar: &str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo3(_: &str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn main() {}
diff --git a/src/test/ui/suggestions/unsized-function-parameter.rs b/src/test/ui/suggestions/unsized-function-parameter.rs
new file mode 100644
index 00000000000..344ee71c1bc
--- /dev/null
+++ b/src/test/ui/suggestions/unsized-function-parameter.rs
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
+fn foo1(bar: str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo2(_bar: str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo3(_: str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn main() {}
diff --git a/src/test/ui/suggestions/unsized-function-parameter.stderr b/src/test/ui/suggestions/unsized-function-parameter.stderr
new file mode 100644
index 00000000000..8cbd8bf3f34
--- /dev/null
+++ b/src/test/ui/suggestions/unsized-function-parameter.stderr
@@ -0,0 +1,42 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-function-parameter.rs:5:9
+   |
+LL | fn foo1(bar: str) {}
+   |         ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo1(bar: &str) {}
+   |              ^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-function-parameter.rs:11:9
+   |
+LL | fn foo2(_bar: str) {}
+   |         ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo2(_bar: &str) {}
+   |               ^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-function-parameter.rs:17:9
+   |
+LL | fn foo3(_: str) {}
+   |         ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo3(_: &str) {}
+   |            ^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/test-panic-abort-disabled.rs b/src/test/ui/test-panic-abort-disabled.rs
index 4adb161d9ee..874dbdb42c3 100644
--- a/src/test/ui/test-panic-abort-disabled.rs
+++ b/src/test/ui/test-panic-abort-disabled.rs
@@ -1,6 +1,6 @@
 // error-pattern:building tests with panic=abort is not supported
 // no-prefer-dynamic
-// compile-flags: --test -Cpanic=abort
+// compile-flags: --test -Cpanic=abort -Zpanic-abort-tests=no
 // run-flags: --test-threads=1
 
 // ignore-wasm no panic or subprocess support
diff --git a/src/test/ui/traits/bound/not-on-bare-trait.rs b/src/test/ui/traits/bound/not-on-bare-trait.rs
index 33c9f2f00cf..08355a55630 100644
--- a/src/test/ui/traits/bound/not-on-bare-trait.rs
+++ b/src/test/ui/traits/bound/not-on-bare-trait.rs
@@ -1,5 +1,5 @@
 trait Foo {
-    fn dummy(&self) { }
+    fn dummy(&self) {}
 }
 
 // This should emit the less confusing error, not the more confusing one.
@@ -7,6 +7,7 @@ trait Foo {
 fn foo(_x: Foo + Send) {
     //~^ ERROR the size for values of type
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/traits/bound/not-on-bare-trait.stderr b/src/test/ui/traits/bound/not-on-bare-trait.stderr
index b8ae88ace02..418e67d56ea 100644
--- a/src/test/ui/traits/bound/not-on-bare-trait.stderr
+++ b/src/test/ui/traits/bound/not-on-bare-trait.stderr
@@ -5,6 +5,8 @@ LL | fn foo(_x: Foo + Send) {
    |            ^^^^^^^^^^ help: use `dyn`: `dyn Foo + Send`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
   --> $DIR/not-on-bare-trait.rs:7:8
diff --git a/src/test/ui/traits/issue-84399-bad-fresh-caching.rs b/src/test/ui/traits/issue-84399-bad-fresh-caching.rs
new file mode 100644
index 00000000000..1494001564f
--- /dev/null
+++ b/src/test/ui/traits/issue-84399-bad-fresh-caching.rs
@@ -0,0 +1,55 @@
+// compile-flags: --crate-type lib
+// check-pass
+//
+// Regression test for issue #84399
+// Tests that we keep the full `ParamEnv` when
+// caching predicates with freshened types in the global cache
+
+use std::marker::PhantomData;
+pub trait Allocator<R> {
+    type Buffer;
+}
+pub struct DefaultAllocator;
+impl <R> Allocator<R> for DefaultAllocator {
+    type Buffer = ();
+}
+pub type Owned<R> = <DefaultAllocator as Allocator<R>>::Buffer;
+pub type MatrixMN<R> = Matrix<R, Owned<R>>;
+pub type Matrix4<N> = Matrix<N, ()>;
+pub struct Matrix<R, S> {
+    pub data: S,
+    _phantoms: PhantomData<R>,
+}
+pub fn set_object_transform(matrix: &Matrix4<()>) {
+    matrix.js_buffer_view();
+}
+pub trait Storable {
+    type Cell;
+    fn slice_to_items(_buffer: &()) -> &[Self::Cell] {
+        unimplemented!()
+    }
+}
+pub type Cell<T> = <T as Storable>::Cell;
+impl<R> Storable for MatrixMN<R>
+where
+    DefaultAllocator: Allocator<R>,
+{
+    type Cell = ();
+}
+pub trait JsBufferView {
+    fn js_buffer_view(&self) -> usize {
+        unimplemented!()
+    }
+}
+impl<R> JsBufferView for [MatrixMN<R>]
+where
+    DefaultAllocator: Allocator<R>,
+    MatrixMN<R>: Storable,
+    [Cell<MatrixMN<R>>]: JsBufferView,
+{
+    fn js_buffer_view(&self) -> usize {
+        <MatrixMN<R> as Storable>::slice_to_items(&()).js_buffer_view()
+    }
+}
+impl JsBufferView for [()] {}
+impl<R> JsBufferView for MatrixMN<R> where DefaultAllocator: Allocator<R> {}
diff --git a/src/test/ui/traits/safety-fn-body.stderr b/src/test/ui/traits/safety-fn-body.stderr
index 4f784a020d9..0aeb186828e 100644
--- a/src/test/ui/traits/safety-fn-body.stderr
+++ b/src/test/ui/traits/safety-fn-body.stderr
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |         *self += 1;
    |         ^^^^^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/issue-84831.rs b/src/test/ui/typeck/issue-84831.rs
new file mode 100644
index 00000000000..c646f710725
--- /dev/null
+++ b/src/test/ui/typeck/issue-84831.rs
@@ -0,0 +1,9 @@
+fn f() {
+    std::<0>; //~ ERROR expected value
+}
+fn j() {
+    std::<_ as _>; //~ ERROR expected value
+    //~^ ERROR expected one of `,` or `>`, found keyword `as`
+}
+
+fn main () {}
diff --git a/src/test/ui/typeck/issue-84831.stderr b/src/test/ui/typeck/issue-84831.stderr
new file mode 100644
index 00000000000..e3cce10a00f
--- /dev/null
+++ b/src/test/ui/typeck/issue-84831.stderr
@@ -0,0 +1,26 @@
+error: expected one of `,` or `>`, found keyword `as`
+  --> $DIR/issue-84831.rs:5:13
+   |
+LL |     std::<_ as _>;
+   |             ^^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     std::<{ _ as _ }>;
+   |           ^        ^
+
+error[E0423]: expected value, found crate `std`
+  --> $DIR/issue-84831.rs:2:5
+   |
+LL |     std::<0>;
+   |     ^^^^^^^^ not a value
+
+error[E0423]: expected value, found crate `std`
+  --> $DIR/issue-84831.rs:5:5
+   |
+LL |     std::<_ as _>;
+   |     ^^^^^^^^^^^^^ not a value
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
index d112d7f4661..88322c3a0a6 100644
--- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
+++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
index 3157783acb6..ad93267ca01 100644
--- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
+++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
@@ -17,7 +17,7 @@ error: dereference of raw pointer is unsafe and requires unsafe block (error E01
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
   --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5
@@ -59,7 +59,7 @@ error: dereference of raw pointer is unsafe and requires unsafe block (error E01
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
   --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr
index 28db83db92a..b2a30f81e05 100644
--- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr
+++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     *p = 0;
    |     ^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr
index e8e82dec0b0..98cb7b876f8 100644
--- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr
+++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     return *p;
    |            ^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
index 4642a7a5fc9..98d7ae9f854 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     *a == b
    |     ^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unwind-no-uwtable.rs b/src/test/ui/unwind-no-uwtable.rs
index f249d3f4574..0440cf488e8 100644
--- a/src/test/ui/unwind-no-uwtable.rs
+++ b/src/test/ui/unwind-no-uwtable.rs
@@ -1,4 +1,5 @@
 // run-pass
+// needs-unwind
 // ignore-windows target requires uwtable
 // ignore-wasm32-bare no proper panic=unwind support
 // compile-flags: -C panic=unwind -C force-unwind-tables=n
diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr
index a4d636bc03c..270233c0c97 100644
--- a/src/test/ui/variance/variance-unused-type-param.stderr
+++ b/src/test/ui/variance/variance-unused-type-param.stderr
@@ -5,6 +5,7 @@ LL | struct SomeStruct<A> { x: u32 }
    |                   ^ unused parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
 
 error[E0392]: parameter `A` is never used
   --> $DIR/variance-unused-type-param.rs:9:15
@@ -13,6 +14,7 @@ LL | enum SomeEnum<A> { Nothing }
    |               ^ unused parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
 
 error[E0392]: parameter `T` is never used
   --> $DIR/variance-unused-type-param.rs:13:15
@@ -21,6 +23,7 @@ LL | enum ListCell<T> {
    |               ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/x86stdcall.rs b/src/test/ui/x86stdcall.rs
index e1136807b3c..2bf4cfc5003 100644
--- a/src/test/ui/x86stdcall.rs
+++ b/src/test/ui/x86stdcall.rs
@@ -27,6 +27,7 @@ pub fn main() {
           target_os = "dragonfly",
           target_os = "emscripten",
           target_os = "freebsd",
+          target_os = "fuchsia",
           target_os = "linux",
           target_os = "macos",
           target_os = "netbsd",
diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs
index fc608eaabcc..54ff38e39db 100644
--- a/src/tools/cargotest/main.rs
+++ b/src/tools/cargotest/main.rs
@@ -85,7 +85,9 @@ fn main() {
     let cargo = &Path::new(cargo);
 
     for test in TEST_REPOS.iter().rev() {
-        test_repo(cargo, out_dir, test);
+        if args[3..].is_empty() || args[3..].iter().any(|s| s.contains(test.name)) {
+            test_repo(cargo, out_dir, test);
+        }
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 5e6733a300f..1fa439639b2 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -101,7 +101,7 @@ pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWri
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
-pub const PERMISSIONS_FROM_MODE: [&str; 7] = ["std", "sys", "unix", "ext", "fs", "PermissionsExt", "from_mode"];
+pub const PERMISSIONS_FROM_MODE: [&str; 7] = ["std", "os", "imp", "unix", "fs", "PermissionsExt", "from_mode"];
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
 pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr
index 923db0664a7..fb4589a48ec 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr
@@ -5,18 +5,26 @@ LL |     for<'a> Dst<A + 'a>: Sized,
    |                 ^^^^^^ help: use `dyn`: `dyn A + 'a`
    |
    = note: `-D bare-trait-objects` implied by `-D warnings`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: trait objects without an explicit `dyn` are deprecated
   --> $DIR/ice-3969.rs:27:16
    |
 LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
    |                ^ help: use `dyn`: `dyn A`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: trait objects without an explicit `dyn` are deprecated
   --> $DIR/ice-3969.rs:27:57
    |
 LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
    |                                                         ^ help: use `dyn`: `dyn A`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
index 129d82652d7..5ad27bb1450 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -77,7 +77,7 @@ fn main() {
     let error_kind = ErrorKind::NotFound;
     match error_kind {
         ErrorKind::NotFound => {},
-        ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | _ => {},
+        ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | ErrorKind::OutOfMemory | _ => {},
     }
     match error_kind {
         ErrorKind::NotFound => {},
@@ -99,6 +99,7 @@ fn main() {
         ErrorKind::Other => {},
         ErrorKind::UnexpectedEof => {},
         ErrorKind::Unsupported => {},
+        ErrorKind::OutOfMemory => {},
         _ => {},
     }
 }
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
index 028ecb63e7e..adca0738bba 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
@@ -99,6 +99,7 @@ fn main() {
         ErrorKind::Other => {},
         ErrorKind::UnexpectedEof => {},
         ErrorKind::Unsupported => {},
+        ErrorKind::OutOfMemory => {},
         _ => {},
     }
 }
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index fd45cad00d6..73f6a4a80c9 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -32,7 +32,7 @@ error: wildcard matches known variants and will also match future added variants
   --> $DIR/wildcard_enum_match_arm.rs:80:9
    |
 LL |         _ => {},
-   |         ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | _`
+   |         ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | ErrorKind::OutOfMemory | _`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index b7693a3cb14..408c0b8da0b 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -171,6 +171,12 @@ impl fmt::Display for Debugger {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum PanicStrategy {
+    Unwind,
+    Abort,
+}
+
 /// Configuration for compiletest
 #[derive(Debug, Clone)]
 pub struct Config {
@@ -249,6 +255,9 @@ pub struct Config {
     /// Force the pass mode of a check/build/run-pass test to this mode.
     pub force_pass_mode: Option<PassMode>,
 
+    /// Explicitly enable or disable running.
+    pub run: Option<bool>,
+
     /// Write out a parseable log of tests that were run
     pub logfile: Option<PathBuf>,
 
@@ -262,6 +271,10 @@ pub struct Config {
     /// Flags to pass to the compiler when building for the target
     pub target_rustcflags: Option<String>,
 
+    /// What panic strategy the target is built with.  Unwind supports Abort, but
+    /// not vice versa.
+    pub target_panic: PanicStrategy,
+
     /// Target system to be tested
     pub target: String,
 
@@ -348,6 +361,15 @@ pub struct Config {
     pub npm: Option<String>,
 }
 
+impl Config {
+    pub fn run_enabled(&self) -> bool {
+        self.run.unwrap_or_else(|| {
+            // Auto-detect whether to run based on the platform.
+            !self.target.ends_with("-fuchsia")
+        })
+    }
+}
+
 #[derive(Debug, Clone)]
 pub struct TestPaths {
     pub file: PathBuf,         // e.g., compile-test/foo/bar/baz.rs
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index f31a24738df..983934d129a 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
 
 use tracing::*;
 
-use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode};
+use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PanicStrategy, PassMode};
 use crate::util;
 use crate::{extract_cdb_version, extract_gdb_version};
 
@@ -85,6 +85,10 @@ impl EarlyProps {
                     props.ignore = true;
                 }
 
+                if !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled") {
+                    props.ignore = true;
+                }
+
                 if !rustc_has_sanitizer_support
                     && config.parse_name_directive(ln, "needs-sanitizer-support")
                 {
@@ -111,6 +115,12 @@ impl EarlyProps {
                     props.ignore = true;
                 }
 
+                if config.target_panic == PanicStrategy::Abort
+                    && config.parse_name_directive(ln, "needs-unwind")
+                {
+                    props.ignore = true;
+                }
+
                 if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
                     props.ignore = true;
                 }
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index d1798a52df7..d53e19f2908 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -5,7 +5,9 @@
 
 extern crate test;
 
-use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
+use crate::common::{
+    expected_output_path, output_base_dir, output_relative_path, PanicStrategy, UI_EXTENSIONS,
+};
 use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths};
 use crate::util::logv;
 use getopts::Options;
@@ -87,6 +89,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "force {check,build,run}-pass tests to this mode.",
             "check | build | run",
         )
+        .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
         .optflag("", "ignored", "run tests marked as ignored")
         .optflag("", "exact", "filters match exactly")
         .optopt(
@@ -96,8 +99,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
              (eg. emulator, valgrind)",
             "PROGRAM",
         )
-        .optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
-        .optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
+        .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
+        .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
+        .optopt("", "target-panic", "what panic strategy the target supports", "unwind | abort")
         .optflag("", "verbose", "run tests verbosely, showing all output")
         .optflag(
             "",
@@ -234,10 +238,21 @@ pub fn parse_config(args: Vec<String>) -> Config {
             mode.parse::<PassMode>()
                 .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode))
         }),
+        run: matches.opt_str("run").and_then(|mode| match mode.as_str() {
+            "auto" => None,
+            "always" => Some(true),
+            "never" => Some(false),
+            _ => panic!("unknown `--run` option `{}` given", mode),
+        }),
         logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
         runtool: matches.opt_str("runtool"),
-        host_rustcflags: matches.opt_str("host-rustcflags"),
-        target_rustcflags: matches.opt_str("target-rustcflags"),
+        host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")),
+        target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")),
+        target_panic: match matches.opt_str("target-panic").as_deref() {
+            Some("unwind") | None => PanicStrategy::Unwind,
+            Some("abort") => PanicStrategy::Abort,
+            _ => panic!("unknown `--target-panic` option `{}` given", mode),
+        },
         target,
         host: opt_str2(matches.opt_str("host")),
         cdb,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index ecbaccf744d..c606aa1dfbf 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -259,6 +259,7 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
 pub fn compute_stamp_hash(config: &Config) -> String {
     let mut hash = DefaultHasher::new();
     config.stage_id.hash(&mut hash);
+    config.run.hash(&mut hash);
 
     match config.debugger {
         Some(Debugger::Cdb) => {
@@ -317,6 +318,7 @@ enum TestOutput {
 enum WillExecute {
     Yes,
     No,
+    Disabled,
 }
 
 /// Should `--emit metadata` be used?
@@ -357,14 +359,17 @@ impl<'test> TestCx<'test> {
     }
 
     fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
-        match self.config.mode {
-            Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => {
-                WillExecute::Yes
-            }
-            MirOpt if pm == Some(PassMode::Run) => WillExecute::Yes,
-            Ui | MirOpt => WillExecute::No,
+        let test_should_run = match self.config.mode {
+            Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true,
+            MirOpt if pm == Some(PassMode::Run) => true,
+            Ui | MirOpt => false,
             mode => panic!("unimplemented for mode {:?}", mode),
-        }
+        };
+        if test_should_run { self.run_if_enabled() } else { WillExecute::No }
+    }
+
+    fn run_if_enabled(&self) -> WillExecute {
+        if self.config.run_enabled() { WillExecute::Yes } else { WillExecute::Disabled }
     }
 
     fn should_run_successfully(&self, pm: Option<PassMode>) -> bool {
@@ -439,12 +444,17 @@ impl<'test> TestCx<'test> {
 
     fn run_rfail_test(&self) {
         let pm = self.pass_mode();
-        let proc_res = self.compile_test(WillExecute::Yes, self.should_emit_metadata(pm));
+        let should_run = self.run_if_enabled();
+        let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm));
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
+
         let proc_res = self.exec_compiled_test();
 
         // The value our Makefile configures valgrind to return on failure
@@ -483,12 +493,17 @@ impl<'test> TestCx<'test> {
 
     fn run_rpass_test(&self) {
         let emit_metadata = self.should_emit_metadata(self.pass_mode());
-        let proc_res = self.compile_test(WillExecute::Yes, emit_metadata);
+        let should_run = self.run_if_enabled();
+        let proc_res = self.compile_test(should_run, emit_metadata);
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
+
         // FIXME(#41968): Move this check to tidy?
         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
         assert!(
@@ -510,12 +525,17 @@ impl<'test> TestCx<'test> {
             return self.run_rpass_test();
         }
 
-        let mut proc_res = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let mut proc_res = self.compile_test(should_run, EmitMetadata::No);
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
+
         let mut new_config = self.config.clone();
         new_config.runtool = new_config.valgrind_path.clone();
         let new_cx = TestCx { config: &new_config, ..*self };
@@ -732,10 +752,14 @@ impl<'test> TestCx<'test> {
 
     fn run_debuginfo_cdb_test_no_opt(&self) {
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compile_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let compile_result = self.compile_test(should_run, EmitMetadata::No);
         if !compile_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compile_result);
         }
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
 
         let exe_file = self.make_exe_name();
 
@@ -826,10 +850,14 @@ impl<'test> TestCx<'test> {
         let mut cmds = commands.join("\n");
 
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compiler_run_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let compiler_run_result = self.compile_test(should_run, EmitMetadata::No);
         if !compiler_run_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compiler_run_result);
         }
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
 
         let exe_file = self.make_exe_name();
 
@@ -1044,10 +1072,14 @@ impl<'test> TestCx<'test> {
 
     fn run_debuginfo_lldb_test_no_opt(&self) {
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compile_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let compile_result = self.compile_test(should_run, EmitMetadata::No);
         if !compile_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compile_result);
         }
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
 
         let exe_file = self.make_exe_name();
 
@@ -1531,7 +1563,9 @@ impl<'test> TestCx<'test> {
         // Only use `make_exe_name` when the test ends up being executed.
         let output_file = match will_execute {
             WillExecute::Yes => TargetLocation::ThisFile(self.make_exe_name()),
-            WillExecute::No => TargetLocation::ThisDirectory(self.output_base_dir()),
+            WillExecute::No | WillExecute::Disabled => {
+                TargetLocation::ThisDirectory(self.output_base_dir())
+            }
         };
 
         let allow_unused = match self.config.mode {
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
index e8fd19a6381..9696e35b796 100644
--- a/src/tools/lint-docs/src/groups.rs
+++ b/src/tools/lint-docs/src/groups.rs
@@ -13,6 +13,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
     ("nonstandard-style", "Violation of standard naming conventions"),
     ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
     ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
+    ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"),
 ];
 
 type LintGroups = BTreeMap<String, BTreeSet<String>>;
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 41f3fe64317a6ef144d2ac33e4e5870d894d603
+Subproject 67c04afc251ad7d80ea22e2056c93349e7e9df5
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 74d1800c25498689c5b5120a1e8495fce0cd0d0
+Subproject 359513ce678efba186972e4f280dbc7046cac15
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 617535393bb5ccc7adf0bac8a3b9a9c306454e7
+Subproject eb741e895f1a73420a401f2495c711afe37d9d1
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
-Subproject 0bd2b1927c2b02a6fe7447d58e897cf1f1a1d41
+Subproject 2a3635d5d1218c726ff58af4bc35418836143f6
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 5a843ea61ec..064dd716521 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -44,12 +44,29 @@ const EXCEPTIONS: &[(&str, &str)] = &[
     ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
 ];
 
+const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
+    ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-jit", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
+    ("libloading", "ISC"),
+    ("mach", "BSD-2-Clause"),
+    ("regalloc", "Apache-2.0 WITH LLVM-exception"),
+    ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
+];
+
 /// These are the root crates that are part of the runtime. The licenses for
 /// these and all their dependencies *must not* be in the exception list.
 const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
 
 /// Crates whose dependencies must be explicitly permitted.
-const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_middle", "rustc_codegen_llvm"];
+const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_driver", "rustc_codegen_llvm"];
 
 /// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
 ///
@@ -72,7 +89,10 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "cc",
     "cfg-if",
     "chalk-derive",
+    "chalk-engine",
     "chalk-ir",
+    "chalk-solve",
+    "chrono",
     "cmake",
     "compiler_builtins",
     "cpuid-bool",
@@ -92,6 +112,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "expect-test",
     "fake-simd",
     "filetime",
+    "fixedbitset",
     "flate2",
     "fortanix-sgx-abi",
     "fuchsia-zircon",
@@ -107,6 +128,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "indexmap",
     "instant",
     "itertools",
+    "itoa",
     "jobserver",
     "kernel32-sys",
     "lazy_static",
@@ -114,6 +136,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "libz-sys",
     "lock_api",
     "log",
+    "matchers",
     "maybe-uninit",
     "md-5",
     "measureme",
@@ -123,6 +146,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "memoffset",
     "miniz_oxide",
     "num_cpus",
+    "num-integer",
+    "num-traits",
     "object",
     "once_cell",
     "opaque-debug",
@@ -130,6 +155,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "parking_lot_core",
     "pathdiff",
     "perf-event-open-sys",
+    "petgraph",
     "pin-project-lite",
     "pkg-config",
     "polonius-engine",
@@ -147,22 +173,28 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "rand_xorshift",
     "redox_syscall",
     "regex",
+    "regex-automata",
     "regex-syntax",
     "remove_dir_all",
+    "rls-data",
+    "rls-span",
     "rustc-demangle",
     "rustc-hash",
     "rustc-rayon",
     "rustc-rayon-core",
     "rustc_version",
+    "ryu",
     "scoped-tls",
     "scopeguard",
     "semver",
     "semver-parser",
     "serde",
     "serde_derive",
+    "serde_json",
     "sha-1",
     "sha2",
     "smallvec",
+    "sharded-slab",
     "snap",
     "stable_deref_trait",
     "stacker",
@@ -172,9 +204,15 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "termcolor",
     "termize",
     "thread_local",
+    "time",
+    "tinyvec",
     "tracing",
     "tracing-attributes",
     "tracing-core",
+    "tracing-log",
+    "tracing-serde",
+    "tracing-subscriber",
+    "tracing-tree",
     "typenum",
     "unicode-normalization",
     "unicode-script",
@@ -189,6 +227,61 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "winapi-i686-pc-windows-gnu",
     "winapi-util",
     "winapi-x86_64-pc-windows-gnu",
+    // this is a false-positive: it's only used by rustfmt, but because it's enabled through a feature, tidy thinks it's used by rustc as well.
+    "yansi-term",
+];
+
+const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
+    "anyhow",
+    "ar",
+    "autocfg",
+    "bitflags",
+    "byteorder",
+    "cfg-if",
+    "cranelift-bforest",
+    "cranelift-codegen",
+    "cranelift-codegen-meta",
+    "cranelift-codegen-shared",
+    "cranelift-entity",
+    "cranelift-frontend",
+    "cranelift-jit",
+    "cranelift-module",
+    "cranelift-native",
+    "cranelift-object",
+    "crc32fast",
+    "errno",
+    "errno-dragonfly",
+    "gcc",
+    "gimli",
+    "hashbrown",
+    "indexmap",
+    "libc",
+    "libloading",
+    "log",
+    "mach",
+    "object",
+    "proc-macro2",
+    "quote",
+    "regalloc",
+    "region",
+    "rustc-hash",
+    "smallvec",
+    "syn",
+    "target-lexicon",
+    "thiserror",
+    "thiserror-impl",
+    "unicode-xid",
+    "winapi",
+    "winapi-i686-pc-windows-gnu",
+    "winapi-x86_64-pc-windows-gnu",
+];
+
+const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
+    // These two crates take quite a long time to build, so don't allow two versions of them
+    // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
+    // under control.
+    "cargo",
+    "rustc-ap-rustc_ast",
 ];
 
 /// Dependency checks.
@@ -201,17 +294,39 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
         .manifest_path(root.join("Cargo.toml"))
         .features(cargo_metadata::CargoOpt::AllFeatures);
     let metadata = t!(cmd.exec());
-    check_exceptions(&metadata, bad);
-    check_dependencies(&metadata, bad);
-    check_crate_duplicate(&metadata, bad);
+    let runtime_ids = compute_runtime_crates(&metadata);
+    check_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad);
+    check_dependencies(&metadata, PERMITTED_DEPENDENCIES, RESTRICTED_DEPENDENCY_CRATES, bad);
+    check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad);
+
+    // Check rustc_codegen_cranelift independently as it has it's own workspace.
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("compiler/rustc_codegen_cranelift/Cargo.toml"))
+        .features(cargo_metadata::CargoOpt::AllFeatures);
+    let metadata = t!(cmd.exec());
+    let runtime_ids = HashSet::new();
+    check_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad);
+    check_dependencies(
+        &metadata,
+        PERMITTED_CRANELIFT_DEPENDENCIES,
+        &["rustc_codegen_cranelift"],
+        bad,
+    );
+    check_crate_duplicate(&metadata, &[], bad);
 }
 
 /// Check that all licenses are in the valid list in `LICENSES`.
 ///
 /// Packages listed in `EXCEPTIONS` are allowed for tools.
-fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
+fn check_exceptions(
+    metadata: &Metadata,
+    exceptions: &[(&str, &str)],
+    runtime_ids: HashSet<&PackageId>,
+    bad: &mut bool,
+) {
     // Validate the EXCEPTIONS list hasn't changed.
-    for (name, license) in EXCEPTIONS {
+    for (name, license) in exceptions {
         // Check that the package actually exists.
         if !metadata.packages.iter().any(|p| p.name == *name) {
             tidy_error!(
@@ -223,13 +338,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
         }
         // Check that the license hasn't changed.
         for pkg in metadata.packages.iter().filter(|p| p.name == *name) {
-            if pkg.name == "fuchsia-cprng" {
-                // This package doesn't declare a license expression. Manual
-                // inspection of the license file is necessary, which appears
-                // to be BSD-3-Clause.
-                assert!(pkg.license.is_none());
-                continue;
-            }
             match &pkg.license {
                 None => {
                     tidy_error!(
@@ -240,14 +348,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
                 }
                 Some(pkg_license) => {
                     if pkg_license.as_str() != *license {
-                        if *name == "crossbeam-queue"
-                            && *license == "MIT/Apache-2.0 AND BSD-2-Clause"
-                        {
-                            // We have two versions of crossbeam-queue and both
-                            // are fine.
-                            continue;
-                        }
-
                         println!("dependency exception `{}` license has changed", name);
                         println!("    previously `{}` now `{}`", license, pkg_license);
                         println!("    update EXCEPTIONS for the new license");
@@ -258,8 +358,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
         }
     }
 
-    let exception_names: Vec<_> = EXCEPTIONS.iter().map(|(name, _license)| *name).collect();
-    let runtime_ids = compute_runtime_crates(metadata);
+    let exception_names: Vec<_> = exceptions.iter().map(|(name, _license)| *name).collect();
 
     // Check if any package does not have a valid license.
     for pkg in &metadata.packages {
@@ -294,9 +393,14 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
 /// `true` if a check failed.
 ///
 /// Specifically, this checks that the dependencies are on the `PERMITTED_DEPENDENCIES`.
-fn check_dependencies(metadata: &Metadata, bad: &mut bool) {
+fn check_dependencies(
+    metadata: &Metadata,
+    permitted_dependencies: &[&'static str],
+    restricted_dependency_crates: &[&'static str],
+    bad: &mut bool,
+) {
     // Check that the PERMITTED_DEPENDENCIES does not have unused entries.
-    for name in PERMITTED_DEPENDENCIES {
+    for name in permitted_dependencies {
         if !metadata.packages.iter().any(|p| p.name == *name) {
             tidy_error!(
                 bad,
@@ -307,12 +411,12 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) {
         }
     }
     // Get the list in a convenient form.
-    let permitted_dependencies: HashSet<_> = PERMITTED_DEPENDENCIES.iter().cloned().collect();
+    let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
 
     // Check dependencies.
     let mut visited = BTreeSet::new();
     let mut unapproved = BTreeSet::new();
-    for &krate in RESTRICTED_DEPENDENCY_CRATES.iter() {
+    for &krate in restricted_dependency_crates.iter() {
         let pkg = pkg_from_name(metadata, krate);
         let mut bad =
             check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
@@ -365,16 +469,12 @@ fn check_crate_dependencies<'a>(
 }
 
 /// Prevents multiple versions of some expensive crates.
-fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
-    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
-        // These two crates take quite a long time to build, so don't allow two versions of them
-        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
-        // under control.
-        "cargo",
-        "rustc-ap-rustc_ast",
-    ];
-
-    for &name in FORBIDDEN_TO_HAVE_DUPLICATES {
+fn check_crate_duplicate(
+    metadata: &Metadata,
+    forbidden_to_have_duplicates: &[&str],
+    bad: &mut bool,
+) {
+    for &name in forbidden_to_have_duplicates {
         let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
         match matches.len() {
             0 => {
@@ -454,16 +554,7 @@ fn normal_deps_of_r<'a>(
         .iter()
         .find(|n| &n.id == pkg_id)
         .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
-    // Don't care about dev-dependencies.
-    // Build dependencies *shouldn't* matter unless they do some kind of
-    // codegen. For now we'll assume they don't.
-    let deps = node.deps.iter().filter(|node_dep| {
-        node_dep
-            .dep_kinds
-            .iter()
-            .any(|kind_info| kind_info.kind == cargo_metadata::DependencyKind::Normal)
-    });
-    for dep in deps {
+    for dep in &node.deps {
         normal_deps_of_r(resolve, &dep.pkg, result);
     }
 }