about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml9
-rw-r--r--.gitmodules2
-rw-r--r--.mailmap2
-rw-r--r--Cargo.lock36
-rw-r--r--RELEASES.md14
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs43
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs55
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs94
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs5
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/misc.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/statics.rs18
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0161.md26
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0602.md2
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs11
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs140
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs8
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs36
-rw-r--r--compiler/rustc_infer/src/traits/util.rs4
-rw-r--r--compiler/rustc_lint/src/builtin.rs1
-rw-r--r--compiler/rustc_lint/src/context.rs11
-rw-r--r--compiler/rustc_lint/src/traits.rs36
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp15
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp20
-rw-r--r--compiler/rustc_macros/src/query.rs104
-rw-r--r--compiler/rustc_middle/src/middle/region.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs33
-rw-r--r--compiler/rustc_middle/src/traits/select.rs5
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs12
-rw-r--r--compiler/rustc_middle/src/ty/error.rs6
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs28
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs5
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs9
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs4
-rw-r--r--compiler/rustc_mir/src/interpret/cast.rs11
-rw-r--r--compiler/rustc_mir/src/transform/add_call_guards.rs4
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/check.rs4
-rw-r--r--compiler/rustc_mir/src/transform/coverage/debug.rs4
-rw-r--r--compiler/rustc_mir/src/transform/remove_zsts.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs38
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs21
-rw-r--r--compiler/rustc_privacy/src/lib.rs139
-rw-r--r--compiler/rustc_query_impl/src/keys.rs10
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs3
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/imports.rs11
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/lib.rs11
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_span/src/lib.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios.rs9
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm32_wasi.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs2
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs32
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs63
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs60
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs172
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs40
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs4
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs4
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs1
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs1
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs3
-rw-r--r--compiler/rustc_typeck/src/check/check.rs27
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs73
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs12
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs1
-rw-r--r--compiler/rustc_typeck/src/check/fallback.rs157
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs80
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs1
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs56
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs8
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs3
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs1
-rw-r--r--compiler/rustc_typeck/src/outlives/explicit.rs1
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs32
-rw-r--r--library/alloc/src/collections/vec_deque/tests.rs33
m---------library/backtrace0
-rw-r--r--library/core/src/iter/traits/collect.rs18
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/src/fs.rs6
-rw-r--r--library/std/src/net/tcp.rs33
-rw-r--r--library/std/src/net/udp.rs6
-rw-r--r--library/std/src/net/udp/tests.rs3
-rw-r--r--library/std/src/os/fd/mod.rs13
-rw-r--r--library/std/src/os/fd/net.rs (renamed from library/std/src/os/unix/net/raw_fd.rs)13
-rw-r--r--library/std/src/os/fd/owned.rs289
-rw-r--r--library/std/src/os/fd/raw.rs (renamed from library/std/src/os/unix/io.rs)37
-rw-r--r--library/std/src/os/linux/process.rs26
-rw-r--r--library/std/src/os/mod.rs3
-rw-r--r--library/std/src/os/unix/io/fd.rs9
-rw-r--r--library/std/src/os/unix/io/fd/tests.rs11
-rw-r--r--library/std/src/os/unix/io/mod.rs57
-rw-r--r--library/std/src/os/unix/io/raw.rs5
-rw-r--r--library/std/src/os/unix/mod.rs2
-rw-r--r--library/std/src/os/unix/net/datagram.rs44
-rw-r--r--library/std/src/os/unix/net/listener.rs14
-rw-r--r--library/std/src/os/unix/net/mod.rs3
-rw-r--r--library/std/src/os/unix/net/stream.rs40
-rw-r--r--library/std/src/os/unix/process.rs74
-rw-r--r--library/std/src/os/wasi/fs.rs30
-rw-r--r--library/std/src/os/wasi/io.rs208
-rw-r--r--library/std/src/os/wasi/io/fd.rs9
-rw-r--r--library/std/src/os/wasi/io/fd/tests.rs11
-rw-r--r--library/std/src/os/wasi/io/mod.rs12
-rw-r--r--library/std/src/os/wasi/io/raw.rs5
-rw-r--r--library/std/src/os/wasi/mod.rs3
-rw-r--r--library/std/src/os/wasi/net/mod.rs3
-rw-r--r--library/std/src/os/windows/io/handle.rs386
-rw-r--r--library/std/src/os/windows/io/mod.rs56
-rw-r--r--library/std/src/os/windows/io/raw.rs (renamed from library/std/src/os/windows/io.rs)27
-rw-r--r--library/std/src/os/windows/io/socket.rs216
-rw-r--r--library/std/src/os/windows/mod.rs7
-rw-r--r--library/std/src/os/windows/process.rs46
-rw-r--r--library/std/src/os/windows/thread.rs4
-rw-r--r--library/std/src/path.rs112
-rw-r--r--library/std/src/path/tests.rs465
-rw-r--r--library/std/src/process.rs18
-rw-r--r--library/std/src/sys/unix/fd.rs115
-rw-r--r--library/std/src/sys/unix/fd/tests.rs3
-rw-r--r--library/std/src/sys/unix/fs.rs77
-rw-r--r--library/std/src/sys/unix/net.rs92
-rw-r--r--library/std/src/sys/unix/pipe.rs63
-rw-r--r--library/std/src/sys/unix/process/process_common.rs15
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs16
-rw-r--r--library/std/src/sys/unix/stdio.rs65
-rw-r--r--library/std/src/sys/wasi/fd.rs163
-rw-r--r--library/std/src/sys/wasi/fs.rs49
-rw-r--r--library/std/src/sys/wasi/net.rs126
-rw-r--r--library/std/src/sys/wasi/stdio.rs19
-rw-r--r--library/std/src/sys/windows/fs.rs73
-rw-r--r--library/std/src/sys/windows/handle.rs122
-rw-r--r--library/std/src/sys/windows/net.rs106
-rw-r--r--library/std/src/sys/windows/os.rs2
-rw-r--r--library/std/src/sys/windows/pipe.rs17
-rw-r--r--library/std/src/sys/windows/process.rs41
-rw-r--r--library/std/src/sys/windows/stdio.rs21
-rw-r--r--library/std/src/sys/windows/thread.rs5
-rw-r--r--library/std/src/sys_common/net.rs42
-rw-r--r--library/std/src/time.rs12
-rw-r--r--library/std/src/time/monotonic.rs115
-rw-r--r--library/std/src/time/tests.rs100
-rw-r--r--src/bootstrap/builder.rs2
-rw-r--r--src/bootstrap/compile.rs4
-rw-r--r--src/bootstrap/native.rs1
-rw-r--r--src/bootstrap/sanity.rs5
-rw-r--r--src/ci/github-actions/ci.yml4
-rwxr-xr-xsrc/ci/scripts/verify-backported-commits.sh150
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/librustdoc/clean/types.rs8
-rw-r--r--src/librustdoc/config.rs5
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/formats/cache.rs13
-rw-r--r--src/librustdoc/html/highlight.rs7
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs550
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css1
-rw-r--r--src/librustdoc/lib.rs7
m---------src/llvm-project0
-rw-r--r--src/test/codegen/array-equality.rs4
-rw-r--r--src/test/codegen/issue-83623-SIMD-PartialEq.rs46
-rw-r--r--src/test/codegen/naked-noinline.rs1
-rw-r--r--src/test/codegen/repeat-trusted-len.rs2
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-1.rs15
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-1.stderr35
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-2.rs18
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-2.stderr11
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-3.rs26
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-3.stderr12
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-4.rs40
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-4.stderr12
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-1.rs23
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-2.rs18
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-3.rs22
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-82034.rs34
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-1.rs23
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-2.rs14
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-3.rs25
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-86953.rs16
-rw-r--r--src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs28
-rw-r--r--src/test/incremental/hashes/trait_impls.rs2
-rw-r--r--src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir1
-rw-r--r--src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff1
-rw-r--r--src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff1
-rw-r--r--src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff1
-rw-r--r--src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff1
-rw-r--r--src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff49
-rw-r--r--src/test/run-make-fulldeps/coverage-llvmir/Makefile2
-rw-r--r--src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt18
-rw-r--r--src/test/run-make/const_fn_mir/dump.mir1
-rw-r--r--src/test/rustdoc-gui/code-tags.goml20
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml2
-rw-r--r--src/test/rustdoc/auxiliary/html_root.rs2
-rw-r--r--src/test/rustdoc/auxiliary/no_html_root.rs1
-rw-r--r--src/test/rustdoc/extern-html-root-url-precedence.rs7
-rw-r--r--src/test/rustdoc/extern-html-root-url.rs18
-rw-r--r--src/test/ui/closures/2229_closure_analysis/issue-87987.rs30
-rw-r--r--src/test/ui/closures/2229_closure_analysis/issue-87987.stderr24
-rw-r--r--src/test/ui/closures/2229_closure_analysis/issue-87988.rs19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match-edge-cases.rs44
-rw-r--r--src/test/ui/codegen/issue-88043-bb-does-not-have-terminator.rs10
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.rs1
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.stderr8
-rw-r--r--src/test/ui/drop-bounds/drop-bounds.stderr14
-rw-r--r--src/test/ui/dst/dst-rvalue.rs6
-rw-r--r--src/test/ui/dst/dst-rvalue.stderr34
-rw-r--r--src/test/ui/enum/enum-discrim-autosizing.rs6
-rw-r--r--src/test/ui/enum/enum-discrim-autosizing.stderr2
-rw-r--r--src/test/ui/error-codes/E0081.rs11
-rw-r--r--src/test/ui/error-codes/E0081.stderr14
-rw-r--r--src/test/ui/error-codes/E0161.edition.stderr8
-rw-r--r--src/test/ui/error-codes/E0161.editionul.stderr9
-rw-r--r--src/test/ui/error-codes/E0161.migrate.stderr8
-rw-r--r--src/test/ui/error-codes/E0161.migrateul.stderr9
-rw-r--r--src/test/ui/error-codes/E0161.nll.stderr8
-rw-r--r--src/test/ui/error-codes/E0161.nllul.stderr9
-rw-r--r--src/test/ui/error-codes/E0161.rs14
-rw-r--r--src/test/ui/error-codes/E0161.zflags.stderr8
-rw-r--r--src/test/ui/error-codes/E0161.zflagsul.stderr9
-rw-r--r--src/test/ui/feature-gates/feature-gate-global_asm.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-global_asm.stderr2
-rw-r--r--src/test/ui/lint/force-warn/allow-warnings.rs (renamed from src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs)2
-rw-r--r--src/test/ui/lint/force-warn/allow-warnings.stderr (renamed from src/test/ui/lint/force-warn/force-allowed-warning.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/allowed-by-default-lint.rs (renamed from src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs)1
-rw-r--r--src/test/ui/lint/force-warn/allowed-by-default-lint.stderr (renamed from src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs10
-rw-r--r--src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr (renamed from src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/allowed-deny-by-default-lint.rs (renamed from src/test/ui/lint/force-warn/force-deny-by-default-lint.rs)3
-rw-r--r--src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr14
-rw-r--r--src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs (renamed from src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs)2
-rw-r--r--src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr (renamed from src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/allowed-warn-by-default-lint.rs (renamed from src/test/ui/lint/force-warn/force-allowed-warning.rs)2
-rw-r--r--src/test/ui/lint/force-warn/allowed-warn-by-default-lint.stderr (renamed from src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/cap-lints-allow.rs (renamed from src/test/ui/lint/force-warn/force-warn-cap-lints-allow.rs)2
-rw-r--r--src/test/ui/lint/force-warn/cap-lints-allow.stderr (renamed from src/test/ui/lint/force-warn/force-warn-cap-lints-allow.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.rs (renamed from src/test/ui/lint/force-warn/force-warn-cap-lints-warn.rs)2
-rw-r--r--src/test/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr (renamed from src/test/ui/lint/force-warn/force-warn-cap-lints-warn.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/deny-by-default-lint.rs (renamed from src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs)2
-rw-r--r--src/test/ui/lint/force-warn/deny-by-default-lint.stderr (renamed from src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allow-warnings.rs (renamed from src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs)3
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allow-warnings.stderr (renamed from src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs12
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr12
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs (renamed from src/test/ui/lint/force-warn/force-warn-group.rs)2
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr (renamed from src/test/ui/lint/force-warn/force-warn-group.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs (renamed from src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs)2
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr (renamed from src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr)2
-rw-r--r--src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs18
-rw-r--r--src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.stderr16
-rw-r--r--src/test/ui/lint/force-warn/warnings-lint-group.rs5
-rw-r--r--src/test/ui/lint/force-warn/warnings-lint-group.stderr9
-rw-r--r--src/test/ui/llvm-asm/issue-69092.rs4
-rw-r--r--src/test/ui/llvm-asm/issue-69092.stderr4
-rw-r--r--src/test/ui/macros/issue-88228.rs22
-rw-r--r--src/test/ui/macros/issue-88228.stderr26
-rw-r--r--src/test/ui/macros/macro-expanded-include/test.rs2
-rw-r--r--src/test/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs9
-rw-r--r--src/test/ui/marker_trait_attr/region-overlap.rs8
-rw-r--r--src/test/ui/marker_trait_attr/region-overlap.stderr29
-rw-r--r--src/test/ui/marker_trait_attr/unsound-overlap.rs25
-rw-r--r--src/test/ui/marker_trait_attr/unsound-overlap.stderr12
-rw-r--r--src/test/ui/proc-macro/derive-helper-shadowing.stderr4
-rw-r--r--src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr6
-rw-r--r--src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs39
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-1.rs12
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr63
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-2.rs4
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr29
-rw-r--r--src/test/ui/type-alias-impl-trait/defining-use-submodule.rs23
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained.rs3
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs6
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr24
-rw-r--r--src/test/ui/type-alias-impl-trait/incomplete-inference.rs15
-rw-r--r--src/test/ui/type-alias-impl-trait/incomplete-inference.stderr21
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-dyn.rs12
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-impl-trait.rs19
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs13
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr9
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-struct.rs12
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-tuple.rs15
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs10
-rw-r--r--src/test/ui/type-alias-impl-trait/unused_generic_param.rs9
-rw-r--r--src/test/ui/type-alias-impl-trait/unused_generic_param.stderr14
-rw-r--r--src/test/ui/typeck/issue-87935-unsized-box-expr.rs10
-rw-r--r--src/test/ui/typeck/issue-87935-unsized-box-expr.stderr12
-rw-r--r--src/test/ui/unsafe/inline_asm.mir.stderr4
-rw-r--r--src/test/ui/unsafe/inline_asm.rs1
-rw-r--r--src/test/ui/unsafe/inline_asm.thir.stderr4
-rwxr-xr-xsrc/tools/cherry-pick.sh34
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_match.rs157
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_some_result.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs34
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs3
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.rs5
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.stderr20
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match2.stderr10
-rw-r--r--src/tools/clippy/tests/ui/if_let_some_result.fixed9
-rw-r--r--src/tools/clippy/tests/ui/if_let_some_result.rs9
-rw-r--r--src/tools/clippy/tests/ui/if_let_some_result.stderr4
m---------src/tools/rust-analyzer54
338 files changed, 6140 insertions, 2425 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a07342ee96c..ff4fa1527e9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -128,6 +128,9 @@ jobs:
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure backported commits are in upstream branches
+        run: src/ci/scripts/verify-backported-commits.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
@@ -499,6 +502,9 @@ jobs:
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure backported commits are in upstream branches
+        run: src/ci/scripts/verify-backported-commits.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
@@ -609,6 +615,9 @@ jobs:
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure backported commits are in upstream branches
+        run: src/ci/scripts/verify-backported-commits.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
diff --git a/.gitmodules b/.gitmodules
index 60ccf9375ee..e22d5762790 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -34,7 +34,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/12.0-2021-07-10
+	branch = rustc/13.0-2021-08-08
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
 	url = https://github.com/rust-embedded/book.git
diff --git a/.mailmap b/.mailmap
index 56ac5296774..2fbb480b85e 100644
--- a/.mailmap
+++ b/.mailmap
@@ -101,6 +101,7 @@ Falco Hirschenberger <falco.hirschenberger@gmail.com> <hirschen@itwm.fhg.de>
 Felix S. Klock II <pnkfelix@pnkfx.org> Felix S Klock II <pnkfelix@pnkfx.org>
 Flaper Fesp <flaper87@gmail.com>
 Florian Wilkens <mrfloya_github@outlook.com> Florian Wilkens <floya@live.de>
+Frank Steffahn <fdsteffahn@gmail.com> <frank.steffahn@stu.uni-kiel.de>
 Gareth Daniel Smith <garethdanielsmith@gmail.com> gareth <gareth@gareth-N56VM.(none)>
 Gareth Daniel Smith <garethdanielsmith@gmail.com> Gareth Smith <garethdanielsmith@gmail.com>
 Georges Dubus <georges.dubus@gmail.com> <georges.dubus@compiletoi.net>
@@ -113,6 +114,7 @@ Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
 Heather <heather@cynede.net> <Cynede@Gentoo.org>
 Heather <heather@cynede.net> <Heather@cynede.net>
 Herman J. Radtke III <herman@hermanradtke.com> Herman J. Radtke III <hermanradtke@gmail.com>
+Hirochika Matsumoto <git@hkmatsumoto.com> <matsujika@gmail.com>
 Ian Jackson <ijackson@chiark.greenend.org.uk> <ian.jackson@citrix.com>
 Ian Jackson <ijackson@chiark.greenend.org.uk> <ijackson+github@slimy.greenend.org.uk>
 Ian Jackson <ijackson@chiark.greenend.org.uk> <iwj@xenproject.org>
diff --git a/Cargo.lock b/Cargo.lock
index 14cb1f1641b..9e0624c57ae 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.14.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423"
+checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
 dependencies = [
  "compiler_builtins",
  "gimli",
@@ -1418,9 +1418,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.23.0"
+version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -2141,9 +2141,13 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.4.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
 
 [[package]]
 name = "memmap2"
@@ -2293,24 +2297,16 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.22.0"
+version = "0.26.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
+checksum = "ee2766204889d09937d00bfbb7fec56bb2a199e2ade963cab19185d8a6104c7c"
 dependencies = [
  "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "object"
-version = "0.25.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
-dependencies = [
  "crc32fast",
  "indexmap",
  "memchr",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
 ]
 
 [[package]]
@@ -3647,7 +3643,7 @@ dependencies = [
  "itertools 0.9.0",
  "jobserver",
  "libc",
- "object 0.25.2",
+ "object",
  "pathdiff",
  "regex",
  "rustc_apfloat",
@@ -4840,7 +4836,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object 0.22.0",
+ "object",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
diff --git a/RELEASES.md b/RELEASES.md
index 1d9ad3160f7..2e7077ed206 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -70,6 +70,7 @@ Cargo
 - [The package definition in `cargo metadata` now includes the `"default_run"`
   field from the manifest.][cargo/9550]
 - [Added `cargo d` as an alias for `cargo doc`.][cargo/9680]
+- [Added `{lib}` as formatting option for `cargo tree` to print the "lib_name" of packages.][cargo/9663]
 
 Rustdoc
 -------
@@ -146,18 +147,13 @@ Version 1.54.0 (2021-07-29)
 Language
 -----------------------
 
-- [You can now use macros for values in built-in attribute macros.][83366]
-  While a seemingly minor addition on its own, this enables a lot of
-  powerful functionality when combined correctly. Most notably you can
-  now include external documentation in your crate by writing the following.
+- [You can now use macros for values in some built-in attributes.][83366]
+  This primarily allows you to call macros within the `#[doc]` attribute. For
+  example, to include external documentation in your crate, you can now write
+  the following:
   ```rust
   #![doc = include_str!("README.md")]
   ```
-  You can also use this to include auto-generated modules:
-  ```rust
-  #[path = concat!(env!("OUT_DIR"), "/generated.rs")]
-  mod generated;
-  ```
 
 - [You can now cast between unsized slice types (and types which contain
   unsized slices) in `const fn`.][85078]
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index d9c4647cba3..fd96858010e 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -31,21 +31,10 @@ pub(crate) fn unsized_info<'tcx>(
             if data_a.principal_def_id() == data_b.principal_def_id() {
                 return old_info;
             }
-            // trait upcasting coercion
 
-            // if both of the two `principal`s are `None`, this function would have returned early above.
-            // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
-            let principal_a = data_a
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-            let principal_b = data_b
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-
-            let vptr_entry_idx = fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
-                principal_a.with_self_ty(fx.tcx, source),
-                principal_b.with_self_ty(fx.tcx, source),
-            ));
+            // trait upcasting coercion
+            let vptr_entry_idx =
+                fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
 
             if let Some(entry_idx) = vptr_entry_idx {
                 let entry_idx = u32::try_from(entry_idx).unwrap();
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 5b4a187a1d5..791604a1827 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -296,39 +296,8 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void
     }
     let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
 
-    // Recover the post-substitution assembly code from LLVM for better
-    // diagnostics.
-    let mut have_source = false;
-    let mut buffer = String::new();
-    let mut level = llvm::DiagnosticLevel::Error;
-    let mut loc = 0;
-    let mut ranges = [0; 8];
-    let mut num_ranges = ranges.len() / 2;
-    let msg = llvm::build_string(|msg| {
-        buffer = llvm::build_string(|buffer| {
-            have_source = llvm::LLVMRustUnpackSMDiagnostic(
-                diag,
-                msg,
-                buffer,
-                &mut level,
-                &mut loc,
-                ranges.as_mut_ptr(),
-                &mut num_ranges,
-            );
-        })
-        .expect("non-UTF8 inline asm");
-    })
-    .expect("non-UTF8 SMDiagnostic");
-
-    let source = have_source.then(|| {
-        let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
-        for i in 0..num_ranges {
-            spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
-        }
-        (buffer, spans)
-    });
-
-    report_inline_asm(cgcx, msg, level, cookie, source);
+    let smdiag = llvm::diagnostic::SrcMgrDiagnostic::unpack(diag);
+    report_inline_asm(cgcx, smdiag.message, smdiag.level, cookie, smdiag.source);
 }
 
 unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
@@ -339,13 +308,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
 
     match llvm::diagnostic::Diagnostic::unpack(info) {
         llvm::diagnostic::InlineAsm(inline) => {
-            report_inline_asm(
-                cgcx,
-                llvm::twine_to_string(inline.message),
-                inline.level,
-                inline.cookie,
-                None,
-            );
+            report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source);
         }
 
         llvm::diagnostic::Optimization(opt) => {
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index cc3cbea4def..a6bdbd11899 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -157,16 +157,18 @@ pub fn compile_codegen_unit(
             }
 
             // Finalize code coverage by injecting the coverage map. Note, the coverage map will
-            // also be added to the `llvm.used` variable, created next.
+            // also be added to the `llvm.compiler.used` variable, created next.
             if cx.sess().instrument_coverage() {
                 cx.coverageinfo_finalize();
             }
 
-            // Create the llvm.used variable
-            // This variable has type [N x i8*] and is stored in the llvm.metadata section
+            // Create the llvm.used and llvm.compiler.used variables.
             if !cx.used_statics().borrow().is_empty() {
                 cx.create_used_variable()
             }
+            if !cx.compiler_used_statics().borrow().is_empty() {
+                cx.create_compiler_used_variable()
+            }
 
             // Finalize debuginfo
             if cx.sess().opts.debuginfo != DebugInfo::None {
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 3ca295f4a7e..e1baf95e1d9 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -474,7 +474,13 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
             }
 
             if attrs.flags.contains(CodegenFnAttrFlags::USED) {
-                self.add_used_global(g);
+                // The semantics of #[used] in Rust only require the symbol to make it into the
+                // object file. It is explicitly allowed for the linker to strip the symbol if it
+                // is dead. As such, use llvm.compiler.used instead of llvm.used.
+                // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
+                // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
+                // in some versions of the gold linker.
+                self.add_compiler_used_global(g);
             }
         }
     }
@@ -484,4 +490,11 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
         let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
         self.used_statics.borrow_mut().push(cast);
     }
+
+    /// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
+    /// an array of i8*.
+    fn add_compiler_used_global(&self, global: &'ll Value) {
+        let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
+        self.compiler_used_statics.borrow_mut().push(cast);
+    }
 }
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 5d56c93f835..35c866d48a4 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -75,6 +75,10 @@ pub struct CodegenCx<'ll, 'tcx> {
     /// See <https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details
     pub used_statics: RefCell<Vec<&'ll Value>>,
 
+    /// Statics that will be placed in the llvm.compiler.used variable
+    /// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
+    pub compiler_used_statics: RefCell<Vec<&'ll Value>>,
+
     /// Mapping of non-scalar types to llvm types and field remapping if needed.
     pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), TypeLowering<'ll>>>,
 
@@ -115,10 +119,6 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
     }
 }
 
-fn strip_powerpc64_vectors(data_layout: String) -> String {
-    data_layout.replace("-v256:256:256-v512:512:512", "")
-}
-
 pub unsafe fn create_module(
     tcx: TyCtxt<'_>,
     llcx: &'ll llvm::Context,
@@ -130,7 +130,18 @@ pub unsafe fn create_module(
 
     let mut target_data_layout = sess.target.data_layout.clone();
     if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
-        target_data_layout = strip_powerpc64_vectors(target_data_layout);
+        target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
+    }
+    if llvm_util::get_version() < (13, 0, 0) {
+        if sess.target.arch == "powerpc64" {
+            target_data_layout = target_data_layout.replace("-S128", "");
+        }
+        if sess.target.arch == "wasm32" {
+            target_data_layout = "e-m:e-p:32:32-i64:64-n32:64-S128".to_string();
+        }
+        if sess.target.arch == "wasm64" {
+            target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string();
+        }
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
@@ -318,6 +329,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             const_globals: Default::default(),
             statics_to_rauw: RefCell::new(Vec::new()),
             used_statics: RefCell::new(Vec::new()),
+            compiler_used_statics: RefCell::new(Vec::new()),
             type_lowering: Default::default(),
             scalar_lltypes: Default::default(),
             pointee_infos: Default::default(),
@@ -340,6 +352,18 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
         self.coverage_cx.as_ref()
     }
+
+    fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
+        let section = cstr!("llvm.metadata");
+        let array = self.const_array(&self.type_ptr_to(self.type_i8()), values);
+
+        unsafe {
+            let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
+            llvm::LLVMSetInitializer(g, array);
+            llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+            llvm::LLVMSetSection(g, section.as_ptr());
+        }
+    }
 }
 
 impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -430,6 +454,10 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         &self.used_statics
     }
 
+    fn compiler_used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
+        &self.compiler_used_statics
+    }
+
     fn set_frame_pointer_type(&self, llfn: &'ll Value) {
         attributes::set_frame_pointer_type(self, llfn)
     }
@@ -440,17 +468,14 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     fn create_used_variable(&self) {
-        let name = cstr!("llvm.used");
-        let section = cstr!("llvm.metadata");
-        let array =
-            self.const_array(&self.type_ptr_to(self.type_i8()), &*self.used_statics.borrow());
+        self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_statics.borrow());
+    }
 
-        unsafe {
-            let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
-            llvm::LLVMSetInitializer(g, array);
-            llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
-            llvm::LLVMSetSection(g, section.as_ptr());
-        }
+    fn create_compiler_used_variable(&self) {
+        self.create_used_variable_impl(
+            cstr!("llvm.compiler.used"),
+            &*self.compiler_used_statics.borrow(),
+        );
     }
 
     fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index aa4db1622b2..1e6e5252b25 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -352,8 +352,8 @@ impl ModuleLlvm {
 impl Drop for ModuleLlvm {
     fn drop(&mut self) {
         unsafe {
-            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
             llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
+            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
index ccd3e42e458..36aa022d746 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
@@ -6,7 +6,8 @@ pub use self::OptimizationDiagnosticKind::*;
 use crate::value::Value;
 use libc::c_uint;
 
-use super::{DiagnosticInfo, Twine};
+use super::{DiagnosticInfo, SMDiagnostic};
+use rustc_span::InnerSpan;
 
 #[derive(Copy, Clone)]
 pub enum OptimizationDiagnosticKind {
@@ -86,36 +87,91 @@ impl OptimizationDiagnostic<'ll> {
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct InlineAsmDiagnostic<'ll> {
+pub struct SrcMgrDiagnostic {
+    pub level: super::DiagnosticLevel,
+    pub message: String,
+    pub source: Option<(String, Vec<InnerSpan>)>,
+}
+
+impl SrcMgrDiagnostic {
+    pub unsafe fn unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic {
+        // Recover the post-substitution assembly code from LLVM for better
+        // diagnostics.
+        let mut have_source = false;
+        let mut buffer = String::new();
+        let mut level = super::DiagnosticLevel::Error;
+        let mut loc = 0;
+        let mut ranges = [0; 8];
+        let mut num_ranges = ranges.len() / 2;
+        let message = super::build_string(|message| {
+            buffer = super::build_string(|buffer| {
+                have_source = super::LLVMRustUnpackSMDiagnostic(
+                    diag,
+                    message,
+                    buffer,
+                    &mut level,
+                    &mut loc,
+                    ranges.as_mut_ptr(),
+                    &mut num_ranges,
+                );
+            })
+            .expect("non-UTF8 inline asm");
+        })
+        .expect("non-UTF8 SMDiagnostic");
+
+        SrcMgrDiagnostic {
+            message,
+            level,
+            source: have_source.then(|| {
+                let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
+                for i in 0..num_ranges {
+                    spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
+                }
+                (buffer, spans)
+            }),
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct InlineAsmDiagnostic {
     pub level: super::DiagnosticLevel,
     pub cookie: c_uint,
-    pub message: &'ll Twine,
-    pub instruction: Option<&'ll Value>,
+    pub message: String,
+    pub source: Option<(String, Vec<InnerSpan>)>,
 }
 
-impl InlineAsmDiagnostic<'ll> {
-    unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
+impl InlineAsmDiagnostic {
+    unsafe fn unpackInlineAsm(di: &'ll DiagnosticInfo) -> Self {
         let mut cookie = 0;
         let mut message = None;
-        let mut instruction = None;
         let mut level = super::DiagnosticLevel::Error;
 
-        super::LLVMRustUnpackInlineAsmDiagnostic(
-            di,
-            &mut level,
-            &mut cookie,
-            &mut message,
-            &mut instruction,
-        );
+        super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);
 
-        InlineAsmDiagnostic { level, cookie, message: message.unwrap(), instruction }
+        InlineAsmDiagnostic {
+            level,
+            cookie,
+            message: super::twine_to_string(message.unwrap()),
+            source: None,
+        }
+    }
+
+    unsafe fn unpackSrcMgr(di: &'ll DiagnosticInfo) -> Self {
+        let mut cookie = 0;
+        let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie));
+        InlineAsmDiagnostic {
+            level: smdiag.level,
+            cookie,
+            message: smdiag.message,
+            source: smdiag.source,
+        }
     }
 }
 
 pub enum Diagnostic<'ll> {
     Optimization(OptimizationDiagnostic<'ll>),
-    InlineAsm(InlineAsmDiagnostic<'ll>),
+    InlineAsm(InlineAsmDiagnostic),
     PGO(&'ll DiagnosticInfo),
     Linker(&'ll DiagnosticInfo),
     Unsupported(&'ll DiagnosticInfo),
@@ -130,7 +186,7 @@ impl Diagnostic<'ll> {
         let kind = super::LLVMRustGetDiagInfoKind(di);
 
         match kind {
-            Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)),
+            Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),
 
             Dk::OptimizationRemark => {
                 Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
@@ -162,6 +218,8 @@ impl Diagnostic<'ll> {
             Dk::Linker => Linker(di),
             Dk::Unsupported => Unsupported(di),
 
+            Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)),
+
             _ => UnknownDiagnostic(di),
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 57173a49107..3f2ed02d90d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -490,6 +490,7 @@ pub enum DiagnosticKind {
     PGOProfile,
     Linker,
     Unsupported,
+    SrcMgr,
 }
 
 /// LLVMRustDiagnosticLevel
@@ -2264,13 +2265,17 @@ extern "C" {
         level_out: &mut DiagnosticLevel,
         cookie_out: &mut c_uint,
         message_out: &mut Option<&'a Twine>,
-        instruction_out: &mut Option<&'a Value>,
     );
 
     #[allow(improper_ctypes)]
     pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
     pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
 
+    pub fn LLVMRustGetSMDiagnostic(
+        DI: &'a DiagnosticInfo,
+        cookie_out: &mut c_uint,
+    ) -> &'a SMDiagnostic;
+
     pub fn LLVMRustSetInlineAsmDiagnosticHandler(
         C: &Context,
         H: InlineAsmDiagHandler,
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 93456443aa0..8a8ece640fc 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -135,6 +135,11 @@ impl CodegenCx<'ll, 'tcx> {
             return false;
         }
 
+        // Match clang by only supporting COFF and ELF for now.
+        if self.tcx.sess.target.is_like_osx {
+            return false;
+        }
+
         // Static relocation model should force copy relocations everywhere.
         if self.tcx.sess.relocation_model() == RelocModel::Static {
             return true;
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 0e036a432ad..930b4dc4d41 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -36,6 +36,6 @@ rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
 
 [dependencies.object]
-version = "0.25.2"
+version = "0.26.1"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 064a51c8f60..a5143a755fe 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -150,19 +150,8 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
             // trait upcasting coercion
 
-            // if both of the two `principal`s are `None`, this function would have returned early above.
-            // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
-            let principal_a = data_a
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-            let principal_b = data_b
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-
-            let vptr_entry_idx = cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((
-                principal_a.with_self_ty(cx.tcx(), source),
-                principal_b.with_self_ty(cx.tcx(), source),
-            ));
+            let vptr_entry_idx =
+                cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
 
             if let Some(entry_idx) = vptr_entry_idx {
                 let ptr_ty = cx.type_i8p();
diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs
index 46f2adbe552..4266e42ec2b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/misc.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs
@@ -16,9 +16,11 @@ pub trait MiscMethods<'tcx>: BackendTypes {
     fn sess(&self) -> &Session;
     fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>;
     fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
+    fn compiler_used_statics(&self) -> &RefCell<Vec<Self::Value>>;
     fn set_frame_pointer_type(&self, llfn: Self::Function);
     fn apply_target_cpu_attr(&self, llfn: Self::Function);
     fn create_used_variable(&self);
+    fn create_compiler_used_variable(&self);
     /// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists.
     fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function>;
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs
index 817fc02d166..a2a3cb56c78 100644
--- a/compiler/rustc_codegen_ssa/src/traits/statics.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs
@@ -6,17 +6,15 @@ pub trait StaticMethods: BackendTypes {
     fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
     fn codegen_static(&self, def_id: DefId, is_mutable: bool);
 
-    /// Mark the given global value as "used", to prevent a backend from potentially removing a
-    /// static variable that may otherwise appear unused.
-    ///
-    /// Static variables in Rust can be annotated with the `#[used]` attribute to direct the `rustc`
-    /// compiler to mark the variable as a "used global".
-    ///
-    /// ```no_run
-    /// #[used]
-    /// static FOO: u32 = 0;
-    /// ```
+    /// Mark the given global value as "used", to prevent the compiler and linker from potentially
+    /// removing a static variable that may otherwise appear unused.
     fn add_used_global(&self, global: Self::Value);
+
+    /// Same as add_used_global(), but only prevent the compiler from potentially removing an
+    /// otherwise unused symbol. The linker is still permitted to drop it.
+    ///
+    /// This corresponds to the semantics of the `#[used]` attribute.
+    fn add_compiler_used_global(&self, global: Self::Value);
 }
 
 pub trait StaticBuilderMethods: BackendTypes {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0161.md b/compiler/rustc_error_codes/src/error_codes/E0161.md
index c2e2f0240f4..ebd2c97698b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0161.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0161.md
@@ -4,11 +4,18 @@ Erroneous code example:
 
 ```compile_fail,E0161
 #![feature(box_syntax)]
+trait Bar {
+    fn f(self);
+}
+
+impl Bar for i32 {
+    fn f(self) {}
+}
 
 fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<[isize]> = box *array;
-    // error: cannot move a value of type [isize]: the size of [isize] cannot
+    let b: Box<dyn Bar> = box (0 as i32);
+    b.f();
+    // error: cannot move a value of type dyn Bar: the size of dyn Bar cannot
     //        be statically determined
 }
 ```
@@ -22,8 +29,17 @@ it around as usual. Example:
 ```
 #![feature(box_syntax)]
 
+trait Bar {
+    fn f(&self);
+}
+
+impl Bar for i32 {
+    fn f(&self) {}
+}
+
 fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<&[isize]> = box array; // ok!
+    let b: Box<dyn Bar> = box (0 as i32);
+    b.f();
+    // ok!
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0602.md b/compiler/rustc_error_codes/src/error_codes/E0602.md
index dcaf251a96b..7980b704cae 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0602.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0602.md
@@ -1,4 +1,4 @@
-An unknown lint was used on the command line.
+An unknown or invalid lint was used on the command line.
 
 Erroneous code example:
 
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index f3c710e0f6a..18294dfad24 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -178,7 +178,7 @@ declare_features! (
     /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`.
     /// This defines the behavior of panics.
     (accepted, panic_handler, "1.30.0", Some(44489), None),
-    /// Allows `#[used]` to preserve symbols (see llvm.used).
+    /// Allows `#[used]` to preserve symbols (see llvm.compiler.used).
     (accepted, used, "1.30.0", Some(40289), None),
     /// Allows `crate` in paths.
     (accepted, crate_in_paths, "1.30.0", Some(45477), None),
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 3a11b5a2144..01d84e287bc 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -22,7 +22,6 @@
 // is also useful to track which value is the "expected" value in
 // terms of error reporting.
 
-use super::equate::Equate;
 use super::glb::Glb;
 use super::lub::Lub;
 use super::sub::Sub;
@@ -30,6 +29,7 @@ use super::type_variable::TypeVariableValue;
 use super::unify_key::replace_if_possible;
 use super::unify_key::{ConstVarValue, ConstVariableValue};
 use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use super::{equate::Equate, type_variable::Diverging};
 use super::{InferCtxt, MiscVariable, TypeTrace};
 
 use crate::traits::{Obligation, PredicateObligations};
@@ -643,8 +643,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                                 .inner
                                 .borrow_mut()
                                 .type_variables()
-                                .new_var(self.for_universe, false, origin);
+                                .new_var(self.for_universe, Diverging::NotDiverging, origin);
                             let u = self.tcx().mk_ty_var(new_var_id);
+
+                            // Record that we replaced `vid` with `new_var_id` as part of a generalization
+                            // operation. This is needed to detect cyclic types. To see why, see the
+                            // docs in the `type_variables` module.
+                            self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
                             Ok(u)
                         }
@@ -881,7 +886,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
                             *self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
                         let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var(
                             self.for_universe,
-                            false,
+                            Diverging::NotDiverging,
                             origin,
                         );
                         let u = self.tcx().mk_ty_var(new_var_id);
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 9b9ded5c6ba..9013bea749a 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -23,7 +23,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
 use rustc_middle::mir::interpret::EvalToConstValueResult;
 use rustc_middle::traits::select;
-use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
@@ -46,7 +46,7 @@ use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, Veri
 use self::region_constraints::{
     RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
 };
-use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind};
 
 pub mod at;
 pub mod canonical;
@@ -671,6 +671,22 @@ pub struct CombinedSnapshot<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    /// calls `tcx.try_unify_abstract_consts` after
+    /// canonicalizing the consts.
+    pub fn try_unify_abstract_consts(
+        &self,
+        a: ty::Unevaluated<'tcx>,
+        b: ty::Unevaluated<'tcx>,
+    ) -> bool {
+        let canonical = self.canonicalize_query(
+            ((a.def, a.substs), (b.def, b.substs)),
+            &mut OriginalQueryValues::default(),
+        );
+        debug!("canonical consts: {:?}", &canonical.value);
+
+        self.tcx.try_unify_abstract_consts(canonical.value)
+    }
+
     pub fn is_in_snapshot(&self) -> bool {
         self.in_snapshot.get()
     }
@@ -679,10 +695,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         t.fold_with(&mut self.freshener())
     }
 
-    pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
+    /// Returns whether `ty` is a diverging type variable or not.
+    /// (If `ty` is not a type variable at all, returns not diverging.)
+    ///
+    /// No attempt is made to resolve `ty`.
+    pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
         match *ty.kind() {
             ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
-            _ => false,
+            _ => Diverging::NotDiverging,
+        }
+    }
+
+    /// Returns the origin of the type variable identified by `vid`, or `None`
+    /// if this is not a type variable.
+    ///
+    /// No attempt is made to resolve `ty`.
+    pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
+        match *ty.kind() {
+            ty::Infer(ty::TyVar(vid)) => {
+                Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
+            }
+            _ => None,
         }
     }
 
@@ -695,28 +728,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         freshen::TypeFreshener::new(self, true)
     }
 
-    pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
-        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
-        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
-        match *ty.kind() {
-            ty::Infer(ty::IntVar(vid)) => {
-                if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() {
-                    Neither
-                } else {
-                    UnconstrainedInt
-                }
-            }
-            ty::Infer(ty::FloatVar(vid)) => {
-                if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() {
-                    Neither
-                } else {
-                    UnconstrainedFloat
-                }
-            }
-            _ => Neither,
-        }
-    }
-
     pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
         let mut inner = self.inner.borrow_mut();
         let mut vars: Vec<Ty<'_>> = inner
@@ -969,29 +980,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         );
     }
 
+    /// Processes a `Coerce` predicate from the fulfillment context.
+    /// This is NOT the preferred way to handle coercion, which is to
+    /// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`).
+    ///
+    /// This method here is actually a fallback that winds up being
+    /// invoked when `FnCtxt::coerce` encounters unresolved type variables
+    /// and records a coercion predicate. Presently, this method is equivalent
+    /// to `subtype_predicate` -- that is, "coercing" `a` to `b` winds up
+    /// actually requiring `a <: b`. This is of course a valid coercion,
+    /// but it's not as flexible as `FnCtxt::coerce` would be.
+    ///
+    /// (We may refactor this in the future, but there are a number of
+    /// practical obstacles. Among other things, `FnCtxt::coerce` presently
+    /// records adjustments that are required on the HIR in order to perform
+    /// the coercion, and we don't currently have a way to manage that.)
+    pub fn coerce_predicate(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        predicate: ty::PolyCoercePredicate<'tcx>,
+    ) -> Option<InferResult<'tcx, ()>> {
+        let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate {
+            a_is_expected: false, // when coercing from `a` to `b`, `b` is expected
+            a: p.a,
+            b: p.b,
+        });
+        self.subtype_predicate(cause, param_env, subtype_predicate)
+    }
+
     pub fn subtype_predicate(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         predicate: ty::PolySubtypePredicate<'tcx>,
     ) -> Option<InferResult<'tcx, ()>> {
-        // Subtle: it's ok to skip the binder here and resolve because
-        // `shallow_resolve` just ignores anything that is not a type
-        // variable, and because type variable's can't (at present, at
+        // Check for two unresolved inference variables, in which case we can
+        // make no progress. This is partly a micro-optimization, but it's
+        // also an opportunity to "sub-unify" the variables. This isn't
+        // *necessary* to prevent cycles, because they would eventually be sub-unified
+        // anyhow during generalization, but it helps with diagnostics (we can detect
+        // earlier that they are sub-unified).
+        //
+        // Note that we can just skip the binders here because
+        // type variables can't (at present, at
         // least) capture any of the things bound by this binder.
         //
-        // NOTE(nmatsakis): really, there is no *particular* reason to do this
-        // `shallow_resolve` here except as a micro-optimization.
-        // Naturally I could not resist.
-        let two_unbound_type_vars = {
-            let a = self.shallow_resolve(predicate.skip_binder().a);
-            let b = self.shallow_resolve(predicate.skip_binder().b);
-            a.is_ty_var() && b.is_ty_var()
-        };
-
-        if two_unbound_type_vars {
-            // Two unbound type variables? Can't make progress.
-            return None;
+        // Note that this sub here is not just for diagnostics - it has semantic
+        // effects as well.
+        let r_a = self.shallow_resolve(predicate.skip_binder().a);
+        let r_b = self.shallow_resolve(predicate.skip_binder().b);
+        match (r_a.kind(), r_b.kind()) {
+            (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
+                self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
+                return None;
+            }
+            _ => {}
         }
 
         Some(self.commit_if_ok(|_snapshot| {
@@ -1020,12 +1064,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         })
     }
 
-    pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
+    pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid {
         self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
     }
 
     pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
+        self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin))
     }
 
     pub fn next_ty_var_in_universe(
@@ -1033,12 +1077,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         origin: TypeVariableOrigin,
         universe: ty::UniverseIndex,
     ) -> Ty<'tcx> {
-        let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin);
+        let vid = self.inner.borrow_mut().type_variables().new_var(
+            universe,
+            Diverging::NotDiverging,
+            origin,
+        );
         self.tcx.mk_ty_var(vid)
     }
 
     pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
+        self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin))
     }
 
     pub fn next_const_var(
@@ -1152,7 +1200,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 // as the substitutions for the default, `(T, U)`.
                 let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
                     self.universe(),
-                    false,
+                    Diverging::NotDiverging,
                     TypeVariableOrigin {
                         kind: TypeVariableOriginKind::TypeParameterDefinition(
                             param.name,
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 20be06adfd0..261c3471a98 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -22,6 +22,7 @@
 //!   constituents)
 
 use crate::infer::combine::ConstEquateRelation;
+use crate::infer::type_variable::Diverging;
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
 use rustc_data_structures::fx::FxHashMap;
@@ -920,7 +921,8 @@ where
                             // Replacing with a new variable in the universe `self.universe`,
                             // it will be unified later with the original type variable in
                             // the universe `_universe`.
-                            let new_var_id = variables.new_var(self.universe, false, origin);
+                            let new_var_id =
+                                variables.new_var(self.universe, Diverging::NotDiverging, origin);
 
                             let u = self.tcx().mk_ty_var(new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 07c75d50d91..4dd5e8ba545 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -19,6 +19,7 @@ pub fn explicit_outlives_bounds<'tcx>(
         .filter_map(move |kind| match kind {
             ty::PredicateKind::Projection(..)
             | ty::PredicateKind::Trait(..)
+            | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::WellFormed(..)
             | ty::PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 2f126d89569..1692d8ee526 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -85,7 +85,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
         let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
         let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
         match (a.kind(), b.kind()) {
-            (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
+            (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
                 // Shouldn't have any LBR here, so we can safely put
                 // this under a binder below without fear of accidental
                 // capture.
@@ -93,11 +93,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
                 assert!(!b.has_escaping_bound_vars());
 
                 // can't make progress on `A <: B` if both A and B are
-                // type variables, so record an obligation. We also
-                // have to record in the `type_variables` tracker that
-                // the two variables are equal modulo subtyping, which
-                // is important to the occurs check later on.
-                infcx.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
+                // type variables, so record an obligation.
                 self.fields.obligations.push(Obligation::new(
                     self.fields.trace.cause.clone(),
                     self.fields.param_env,
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 13b78b26af4..d2b0bdaf978 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -75,14 +75,30 @@ pub struct TypeVariableStorage<'tcx> {
     ///     ?1 <: ?3
     ///     Box<?3> <: ?1
     ///
-    /// This works because `?1` and `?3` are unified in the
-    /// `sub_relations` relation (not in `eq_relations`). Then when we
-    /// process the `Box<?3> <: ?1` constraint, we do an occurs check
-    /// on `Box<?3>` and find a potential cycle.
+    /// Without this second table, what would happen in a case like
+    /// this is that we would instantiate `?1` with a generalized
+    /// type like `Box<?6>`. We would then relate `Box<?3> <: Box<?6>`
+    /// and infer that `?3 <: ?6`. Next, since `?1` was instantiated,
+    /// we would process `?1 <: ?3`, generalize `?1 = Box<?6>` to `Box<?9>`,
+    /// and instantiate `?3` with `Box<?9>`. Finally, we would relate
+    /// `?6 <: ?9`. But now that we instantiated `?3`, we can process
+    /// `?3 <: ?6`, which gives us `Box<?9> <: ?6`... and the cycle
+    /// continues. (This is `occurs-check-2.rs`.)
+    ///
+    /// What prevents this cycle is that when we generalize
+    /// `Box<?3>` to `Box<?6>`, we also sub-unify `?3` and `?6`
+    /// (in the generalizer). When we then process `Box<?6> <: ?3`,
+    /// the occurs check then fails because `?6` and `?3` are sub-unified,
+    /// and hence generalization fails.
     ///
     /// This is reasonable because, in Rust, subtypes have the same
     /// "skeleton" and hence there is no possible type such that
     /// (e.g.)  `Box<?3> <: ?3` for any `?3`.
+    ///
+    /// In practice, we sometimes sub-unify variables in other spots, such
+    /// as when processing subtype predicates. This is not necessary but is
+    /// done to aid diagnostics, as it allows us to be more effective when
+    /// we guide the user towards where they should insert type hints.
     sub_relations: ut::UnificationTableStorage<ty::TyVid>,
 }
 
@@ -119,7 +135,13 @@ pub enum TypeVariableOriginKind {
 
 pub(crate) struct TypeVariableData {
     origin: TypeVariableOrigin,
-    diverging: bool,
+    diverging: Diverging,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum Diverging {
+    NotDiverging,
+    Diverges,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -173,7 +195,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
     ///
     /// Note that this function does not return care whether
     /// `vid` has been unified with something else or not.
-    pub fn var_diverges(&self, vid: ty::TyVid) -> bool {
+    pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging {
         self.storage.values.get(vid.index as usize).diverging
     }
 
@@ -238,7 +260,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
     pub fn new_var(
         &mut self,
         universe: ty::UniverseIndex,
-        diverging: bool,
+        diverging: Diverging,
         origin: TypeVariableOrigin,
     ) -> ty::TyVid {
         let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 3139e121163..3a25cb66896 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -158,6 +158,10 @@ impl Elaborator<'tcx> {
                 // Currently, we do not "elaborate" predicates like `X <: Y`,
                 // though conceivably we might.
             }
+            ty::PredicateKind::Coerce(..) => {
+                // Currently, we do not "elaborate" predicates like `X -> Y`,
+                // though conceivably we might.
+            }
             ty::PredicateKind::Projection(..) => {
                 // Nothing to elaborate in a projection predicate.
             }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 77c7040e6a7..5a72db7752d 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1652,6 +1652,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     ObjectSafe(..) |
                     ClosureKind(..) |
                     Subtype(..) |
+                    Coerce(..) |
                     ConstEvaluatable(..) |
                     ConstEquate(..) |
                     TypeWellFormedFromEnv(..) => continue,
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 47c6e904cd7..c2a46e997df 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -332,7 +332,16 @@ impl LintStore {
         crate_attrs: &[ast::Attribute],
     ) {
         let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
-
+        if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn {
+            return struct_span_err!(
+                sess,
+                DUMMY_SP,
+                E0602,
+                "`{}` lint group is not supported with ´--force-warn´",
+                crate::WARNINGS.name_lower()
+            )
+            .emit();
+        }
         let db = match self.check_lint_name(sess, lint_name_only, tool_name, crate_attrs) {
             CheckLintNameResult::Ok(_) => None,
             CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 2c039b6d05d..edb158dd378 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -18,23 +18,27 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// `Drop` bounds do not really accomplish anything. A type may have
-    /// compiler-generated drop glue without implementing the `Drop` trait
-    /// itself. The `Drop` trait also only has one method, `Drop::drop`, and
-    /// that function is by fiat not callable in user code. So there is really
-    /// no use case for using `Drop` in trait bounds.
+    /// A generic trait bound of the form `T: Drop` is most likely misleading
+    /// and not what the programmer intended (they probably should have used
+    /// `std::mem::needs_drop` instead).
     ///
-    /// The most likely use case of a drop bound is to distinguish between
-    /// types that have destructors and types that don't. Combined with
-    /// specialization, a naive coder would write an implementation that
-    /// assumed a type could be trivially dropped, then write a specialization
-    /// for `T: Drop` that actually calls the destructor. Except that doing so
-    /// is not correct; String, for example, doesn't actually implement Drop,
-    /// but because String contains a Vec, assuming it can be trivially dropped
-    /// will leak memory.
+    /// `Drop` bounds do not actually indicate whether a type can be trivially
+    /// dropped or not, because a composite type containing `Drop` types does
+    /// not necessarily implement `Drop` itself. Naïvely, one might be tempted
+    /// to write an implementation that assumes that a type can be trivially
+    /// dropped while also supplying a specialization for `T: Drop` that
+    /// actually calls the destructor. However, this breaks down e.g. when `T`
+    /// is `String`, which does not implement `Drop` itself but contains a
+    /// `Vec`, which does implement `Drop`, so assuming `T` can be trivially
+    /// dropped would lead to a memory leak here.
+    ///
+    /// Furthermore, the `Drop` trait only contains one method, `Drop::drop`,
+    /// which may not be called explicitly in user code (`E0040`), so there is
+    /// really no use case for using `Drop` in trait bounds, save perhaps for
+    /// some obscure corner cases, which can use `#[allow(drop_bounds)]`.
     pub DROP_BOUNDS,
     Warn,
-    "bounds of the form `T: Drop` are useless"
+    "bounds of the form `T: Drop` are most likely incorrect"
 }
 
 declare_lint! {
@@ -102,8 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                         None => return,
                     };
                     let msg = format!(
-                        "bounds on `{}` are useless, consider instead \
-                         using `{}` to detect if a type has a destructor",
+                        "bounds on `{}` are most likely incorrect, consider instead \
+                         using `{}` to detect whether a type can be trivially dropped",
                         predicate,
                         cx.tcx.def_path_str(needs_drop)
                     );
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index f563870e3e0..b3f86f3295a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -922,9 +922,17 @@ LLVMRustOptimizeWithNewPassManager(
           MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
           MPM.addPass(ModuleAddressSanitizerPass(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
+#if LLVM_VERSION_GE(14, 0)
+          AddressSanitizerOptions opts(/*CompileKernel=*/false,
+                                       SanitizerOptions->SanitizeAddressRecover,
+                                       /*UseAfterScope=*/true,
+                                       AsanDetectStackUseAfterReturnMode::Runtime);
+          MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(opts)));
+#else
           MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
               /*UseAfterScope=*/true)));
+#endif
         }
       );
 #else
@@ -952,8 +960,15 @@ LLVMRustOptimizeWithNewPassManager(
 #if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
+#if LLVM_VERSION_GE(14, 0)
+          HWAddressSanitizerOptions opts(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover,
+              /*DisableOptimization=*/false);
+          MPM.addPass(HWAddressSanitizerPass(opts));
+#else
           MPM.addPass(HWAddressSanitizerPass(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
+#endif
         }
       );
 #else
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 52566b19eca..4edfed03401 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1114,15 +1114,13 @@ extern "C" void
 LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI,
                                   LLVMRustDiagnosticLevel *LevelOut,
                                   unsigned *CookieOut,
-                                  LLVMTwineRef *MessageOut,
-                                  LLVMValueRef *InstructionOut) {
+                                  LLVMTwineRef *MessageOut) {
   // Undefined to call this not on an inline assembly diagnostic!
   llvm::DiagnosticInfoInlineAsm *IA =
       static_cast<llvm::DiagnosticInfoInlineAsm *>(unwrap(DI));
 
   *CookieOut = IA->getLocCookie();
   *MessageOut = wrap(&IA->getMsgStr());
-  *InstructionOut = wrap(IA->getInstruction());
 
   switch (IA->getSeverity()) {
     case DS_Error:
@@ -1165,6 +1163,7 @@ enum class LLVMRustDiagnosticKind {
   PGOProfile,
   Linker,
   Unsupported,
+  SrcMgr,
 };
 
 static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
@@ -1193,6 +1192,10 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
     return LLVMRustDiagnosticKind::Linker;
   case DK_Unsupported:
     return LLVMRustDiagnosticKind::Unsupported;
+#if LLVM_VERSION_GE(13, 0)
+  case DK_SrcMgr:
+    return LLVMRustDiagnosticKind::SrcMgr;
+#endif
   default:
     return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
                ? LLVMRustDiagnosticKind::OptimizationRemarkOther
@@ -1280,6 +1283,17 @@ extern "C" void LLVMRustSetInlineAsmDiagnosticHandler(
 #endif
 }
 
+extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(
+    LLVMDiagnosticInfoRef DI, unsigned *Cookie) {
+#if LLVM_VERSION_GE(13, 0)
+  llvm::DiagnosticInfoSrcMgr *SM = static_cast<llvm::DiagnosticInfoSrcMgr *>(unwrap(DI));
+  *Cookie = SM->getLocCookie();
+  return wrap(&SM->getSMDiag());
+#else
+  report_fatal_error("Shouldn't get called on older versions");
+#endif
+}
+
 extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef,
                                            RustStringRef MessageOut,
                                            RustStringRef BufferOut,
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index dcd36d61bc6..7ad36973f46 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -1,6 +1,6 @@
 use proc_macro::TokenStream;
 use proc_macro2::{Delimiter, TokenTree};
-use quote::quote;
+use quote::{quote, quote_spanned};
 use syn::parse::{Parse, ParseStream, Result};
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
@@ -42,19 +42,19 @@ enum QueryModifier {
     LoadCached(Ident, Ident, Block),
 
     /// A cycle error for this query aborting the compilation with a fatal error.
-    FatalCycle,
+    FatalCycle(Ident),
 
     /// A cycle error results in a delay_bug call
-    CycleDelayBug,
+    CycleDelayBug(Ident),
 
     /// Don't hash the result, instead just mark a query red if it runs
-    NoHash,
+    NoHash(Ident),
 
     /// Generate a dep node based on the dependencies of the query
-    Anon,
+    Anon(Ident),
 
     /// Always evaluate the query, ignoring its dependencies
-    EvalAlways,
+    EvalAlways(Ident),
 }
 
 impl Parse for QueryModifier {
@@ -111,15 +111,15 @@ impl Parse for QueryModifier {
             let ty = args.parse()?;
             Ok(QueryModifier::Storage(ty))
         } else if modifier == "fatal_cycle" {
-            Ok(QueryModifier::FatalCycle)
+            Ok(QueryModifier::FatalCycle(modifier))
         } else if modifier == "cycle_delay_bug" {
-            Ok(QueryModifier::CycleDelayBug)
+            Ok(QueryModifier::CycleDelayBug(modifier))
         } else if modifier == "no_hash" {
-            Ok(QueryModifier::NoHash)
+            Ok(QueryModifier::NoHash(modifier))
         } else if modifier == "anon" {
-            Ok(QueryModifier::Anon)
+            Ok(QueryModifier::Anon(modifier))
         } else if modifier == "eval_always" {
-            Ok(QueryModifier::EvalAlways)
+            Ok(QueryModifier::EvalAlways(modifier))
         } else {
             Err(Error::new(modifier.span(), "unknown query modifier"))
         }
@@ -203,19 +203,19 @@ struct QueryModifiers {
     load_cached: Option<(Ident, Ident, Block)>,
 
     /// A cycle error for this query aborting the compilation with a fatal error.
-    fatal_cycle: bool,
+    fatal_cycle: Option<Ident>,
 
     /// A cycle error results in a delay_bug call
-    cycle_delay_bug: bool,
+    cycle_delay_bug: Option<Ident>,
 
     /// Don't hash the result, instead just mark a query red if it runs
-    no_hash: bool,
+    no_hash: Option<Ident>,
 
     /// Generate a dep node based on the dependencies of the query
-    anon: bool,
+    anon: Option<Ident>,
 
     // Always evaluate the query, ignoring its dependencies
-    eval_always: bool,
+    eval_always: Option<Ident>,
 }
 
 /// Process query modifiers into a struct, erroring on duplicates
@@ -224,11 +224,11 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
     let mut storage = None;
     let mut cache = None;
     let mut desc = None;
-    let mut fatal_cycle = false;
-    let mut cycle_delay_bug = false;
-    let mut no_hash = false;
-    let mut anon = false;
-    let mut eval_always = false;
+    let mut fatal_cycle = None;
+    let mut cycle_delay_bug = None;
+    let mut no_hash = None;
+    let mut anon = None;
+    let mut eval_always = None;
     for modifier in query.modifiers.0.drain(..) {
         match modifier {
             QueryModifier::LoadCached(tcx, id, block) => {
@@ -289,35 +289,35 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
                 }
                 desc = Some((tcx, list));
             }
-            QueryModifier::FatalCycle => {
-                if fatal_cycle {
+            QueryModifier::FatalCycle(ident) => {
+                if fatal_cycle.is_some() {
                     panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
                 }
-                fatal_cycle = true;
+                fatal_cycle = Some(ident);
             }
-            QueryModifier::CycleDelayBug => {
-                if cycle_delay_bug {
+            QueryModifier::CycleDelayBug(ident) => {
+                if cycle_delay_bug.is_some() {
                     panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name);
                 }
-                cycle_delay_bug = true;
+                cycle_delay_bug = Some(ident);
             }
-            QueryModifier::NoHash => {
-                if no_hash {
+            QueryModifier::NoHash(ident) => {
+                if no_hash.is_some() {
                     panic!("duplicate modifier `no_hash` for query `{}`", query.name);
                 }
-                no_hash = true;
+                no_hash = Some(ident);
             }
-            QueryModifier::Anon => {
-                if anon {
+            QueryModifier::Anon(ident) => {
+                if anon.is_some() {
                     panic!("duplicate modifier `anon` for query `{}`", query.name);
                 }
-                anon = true;
+                anon = Some(ident);
             }
-            QueryModifier::EvalAlways => {
-                if eval_always {
+            QueryModifier::EvalAlways(ident) => {
+                if eval_always.is_some() {
                     panic!("duplicate modifier `eval_always` for query `{}`", query.name);
                 }
-                eval_always = true;
+                eval_always = Some(ident);
             }
         }
     }
@@ -454,31 +454,39 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
         let mut attributes = Vec::new();
 
         // Pass on the fatal_cycle modifier
-        if modifiers.fatal_cycle {
-            attributes.push(quote! { fatal_cycle });
+        if let Some(fatal_cycle) = &modifiers.fatal_cycle {
+            attributes.push(quote! { #fatal_cycle });
         };
         // Pass on the storage modifier
         if let Some(ref ty) = modifiers.storage {
-            attributes.push(quote! { storage(#ty) });
+            let span = ty.span();
+            attributes.push(quote_spanned! {span=> storage(#ty) });
         };
         // Pass on the cycle_delay_bug modifier
-        if modifiers.cycle_delay_bug {
-            attributes.push(quote! { cycle_delay_bug });
+        if let Some(cycle_delay_bug) = &modifiers.cycle_delay_bug {
+            attributes.push(quote! { #cycle_delay_bug });
         };
         // Pass on the no_hash modifier
-        if modifiers.no_hash {
-            attributes.push(quote! { no_hash });
+        if let Some(no_hash) = &modifiers.no_hash {
+            attributes.push(quote! { #no_hash });
         };
         // Pass on the anon modifier
-        if modifiers.anon {
-            attributes.push(quote! { anon });
+        if let Some(anon) = &modifiers.anon {
+            attributes.push(quote! { #anon });
         };
         // Pass on the eval_always modifier
-        if modifiers.eval_always {
-            attributes.push(quote! { eval_always });
+        if let Some(eval_always) = &modifiers.eval_always {
+            attributes.push(quote! { #eval_always });
         };
 
-        let attribute_stream = quote! {#(#attributes),*};
+        // This uses the span of the query definition for the commas,
+        // which can be important if we later encounter any ambiguity
+        // errors with any of the numerous macro_rules! macros that
+        // we use. Using the call-site span would result in a span pointing
+        // at the entire `rustc_queries!` invocation, which wouldn't
+        // be very useful.
+        let span = name.span();
+        let attribute_stream = quote_spanned! {span=> #(#attributes),*};
         let doc_comments = query.doc_comments.iter();
         // Add the query to the group
         query_stream.extend(quote! {
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index f44267a404b..ffa26b9f299 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -189,7 +189,7 @@ impl Scope {
                 // To avoid issues with macro-generated spans, the span
                 // of the statement must be nested in that of the block.
                 if span.lo() <= stmt_span.lo() && stmt_span.lo() <= span.hi() {
-                    return Span::new(stmt_span.lo(), span.hi(), span.ctxt());
+                    return span.with_lo(stmt_span.lo());
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5b37556985b..85b1274da10 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -987,9 +987,9 @@ rustc_queries! {
         desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
     }
 
-    query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>)) -> Option<usize> {
-        desc { |tcx| "finding the slot within vtable for trait {} vtable ptr during trait upcasting coercion from {} vtable",
-            tcx.def_path_str(key.1.def_id()), tcx.def_path_str(key.0.def_id()) }
+    query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::Ty<'tcx>, ty::Ty<'tcx>)) -> Option<usize> {
+        desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
+            key.1, key.0 }
     }
 
     query codegen_fulfill_obligation(
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index a4a2e824637..469da858ccf 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -225,6 +225,8 @@ pub enum ObligationCauseCode<'tcx> {
     SizedReturnType,
     /// Yield type must be `Sized`.
     SizedYieldType,
+    /// Box expression result type must be `Sized`.
+    SizedBoxType,
     /// Inline asm operand type must be `Sized`.
     InlineAsmSized,
     /// `[T, ..n]` implies that `T` must be `Copy`.
@@ -503,6 +505,9 @@ pub enum ImplSource<'tcx, N> {
     /// Successful resolution for a builtin trait.
     Builtin(ImplSourceBuiltinData<N>),
 
+    /// ImplSource for trait upcasting coercion
+    TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>),
+
     /// ImplSource automatically generated for a closure. The `DefId` is the ID
     /// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the
     /// impl is generated by the compiler and does not appear in the source.
@@ -538,6 +543,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
             | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
             ImplSource::TraitAlias(d) => d.nested,
+            ImplSource::TraitUpcasting(d) => d.nested,
         }
     }
 
@@ -554,6 +560,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
             | ImplSource::Pointee(ImplSourcePointeeData) => &[],
             ImplSource::TraitAlias(d) => &d.nested[..],
+            ImplSource::TraitUpcasting(d) => &d.nested[..],
         }
     }
 
@@ -605,6 +612,13 @@ impl<'tcx, N> ImplSource<'tcx, N> {
                 substs: d.substs,
                 nested: d.nested.into_iter().map(f).collect(),
             }),
+            ImplSource::TraitUpcasting(d) => {
+                ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
+                    upcast_trait_ref: d.upcast_trait_ref,
+                    vtable_vptr_slot: d.vtable_vptr_slot,
+                    nested: d.nested.into_iter().map(f).collect(),
+                })
+            }
         }
     }
 }
@@ -651,6 +665,20 @@ pub struct ImplSourceAutoImplData<N> {
 }
 
 #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+pub struct ImplSourceTraitUpcastingData<'tcx, N> {
+    /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
+    pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
+
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
+    /// within that vtable.
+    pub vtable_vptr_slot: Option<usize>,
+
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceBuiltinData<N> {
     pub nested: Vec<N>,
 }
@@ -661,8 +689,9 @@ pub struct ImplSourceObjectData<'tcx, N> {
     pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
 
     /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits; this is the start of
-    /// `upcast_trait_ref`'s methods in that vtable.
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
+    /// in that vtable.
     pub vtable_base: usize,
 
     pub nested: Vec<N>,
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 924568a01a7..3b7c201f3ee 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -135,6 +135,11 @@ pub enum SelectionCandidate<'tcx> {
     /// `rustc_infer::traits::util::supertraits`.
     ObjectCandidate(usize),
 
+    /// Perform trait upcasting coercion of `dyn Trait` to a supertrait of `Trait`.
+    /// The index is the position in the iterator returned by
+    /// `rustc_infer::traits::util::supertraits`.
+    TraitUpcastingUnsizeCandidate(usize),
+
     BuiltinObjectCandidate,
 
     BuiltinUnsizeCandidate,
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index 4f978e63630..aa16e14fedc 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -30,6 +30,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
             super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
 
             super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
+
+            super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
         }
     }
 }
@@ -70,6 +72,16 @@ impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> {
     }
 }
 
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})",
+            self.upcast_trait_ref, self.vtable_vptr_slot, self.nested
+        )
+    }
+}
+
 impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 3846d9ffdba..1aa6c84dbc4 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -71,12 +71,6 @@ pub enum TypeError<'tcx> {
     TargetFeatureCast(DefId),
 }
 
-pub enum UnconstrainedNumeric {
-    UnconstrainedFloat,
-    UnconstrainedInt,
-    Neither,
-}
-
 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
 /// afterwards to present additional details, particularly when it comes to lifetime-related
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 391c8292bd5..04df706d908 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -231,6 +231,10 @@ impl FlagComputation {
                 self.add_ty(a);
                 self.add_ty(b);
             }
+            ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+                self.add_ty(a);
+                self.add_ty(b);
+            }
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
                 self.add_projection_ty(projection_ty);
                 self.add_ty(ty);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 0906cffa05c..9fcf35b7320 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -485,8 +485,22 @@ pub enum PredicateKind<'tcx> {
     ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind),
 
     /// `T1 <: T2`
+    ///
+    /// This obligation is created most often when we have two
+    /// unresolved type variables and hence don't have enough
+    /// information to process the subtyping obligation yet.
     Subtype(SubtypePredicate<'tcx>),
 
+    /// `T1` coerced to `T2`
+    ///
+    /// Like a subtyping obligation, this is created most often
+    /// when we have two unresolved type variables and hence
+    /// don't have enough information to process the coercion
+    /// obligation yet. At the moment, we actually process coercions
+    /// very much like subtyping and don't handle the full coercion
+    /// logic.
+    Coerce(CoercePredicate<'tcx>),
+
     /// Constant initializer must evaluate successfully.
     ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
 
@@ -655,6 +669,9 @@ pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'t
 pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
 pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
 
+/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
+/// whether the `a` type is the type that we should label as "expected" when
+/// presenting user diagnostics.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct SubtypePredicate<'tcx> {
@@ -664,6 +681,15 @@ pub struct SubtypePredicate<'tcx> {
 }
 pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
 
+/// Encodes that we have to coerce *from* the `a` type to the `b` type.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable)]
+pub struct CoercePredicate<'tcx> {
+    pub a: Ty<'tcx>,
+    pub b: Ty<'tcx>,
+}
+pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
+
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
 ///
@@ -806,6 +832,7 @@ impl<'tcx> Predicate<'tcx> {
             }
             PredicateKind::Projection(..)
             | PredicateKind::Subtype(..)
+            | PredicateKind::Coerce(..)
             | PredicateKind::RegionOutlives(..)
             | PredicateKind::WellFormed(..)
             | PredicateKind::ObjectSafe(..)
@@ -824,6 +851,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Trait(..)
             | PredicateKind::Projection(..)
             | PredicateKind::Subtype(..)
+            | PredicateKind::Coerce(..)
             | PredicateKind::RegionOutlives(..)
             | PredicateKind::WellFormed(..)
             | PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index c96621338f5..8558d6bb00e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2236,6 +2236,10 @@ define_print_and_forward_display! {
         p!(print(self.a), " <: ", print(self.b))
     }
 
+    ty::CoercePredicate<'tcx> {
+        p!(print(self.a), " -> ", print(self.b))
+    }
+
     ty::TraitPredicate<'tcx> {
         p!(print(self.trait_ref.self_ty()), ": ",
            print(self.trait_ref.print_only_trait_path()))
@@ -2268,6 +2272,7 @@ define_print_and_forward_display! {
                 p!(print(data))
             }
             ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+            ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
             ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
             ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
             ty::PredicateKind::Projection(predicate) => p!(print(predicate)),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 62397752db2..a46cac1e7f7 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -179,6 +179,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> {
         match *self {
             ty::PredicateKind::Trait(ref a) => a.fmt(f),
             ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
+            ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
             ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
             ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
             ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
@@ -380,6 +381,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> {
+    type Lifted = ty::CoercePredicate<'tcx>;
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::CoercePredicate<'tcx>> {
+        tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b })
+    }
+}
+
 impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
     type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -420,6 +428,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
         match self {
             ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait),
             ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
+            ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce),
             ty::PredicateKind::RegionOutlives(data) => {
                 tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
             }
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index d05e0135dfe..35bb6ef6c2d 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -1893,9 +1893,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
                 // While this is located in `nll::typeck` this error is not
                 // an NLL error, it's a required check to prevent creation
-                // of unsized rvalues in certain cases:
-                // * operand of a box expression
-                // * callee in a call expression
+                // of unsized rvalues in a call expression.
                 diag.emit();
             }
         }
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs
index cee4c2e30aa..697e98311e2 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_mir/src/interpret/cast.rs
@@ -275,16 +275,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     return self.write_immediate(*val, dest);
                 }
                 // trait upcasting coercion
-                let principal_a = data_a.principal().expect(
-                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
-                );
-                let principal_b = data_b.principal().expect(
-                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
-                );
-
                 let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
-                    principal_a.with_self_ty(*self.tcx, src_pointee_ty),
-                    principal_b.with_self_ty(*self.tcx, src_pointee_ty),
+                    src_pointee_ty,
+                    dest_pointee_ty,
                 ));
 
                 if let Some(entry_idx) = vptr_entry_idx {
diff --git a/compiler/rustc_mir/src/transform/add_call_guards.rs b/compiler/rustc_mir/src/transform/add_call_guards.rs
index 1dddaeb89e6..12ee6bb4c67 100644
--- a/compiler/rustc_mir/src/transform/add_call_guards.rs
+++ b/compiler/rustc_mir/src/transform/add_call_guards.rs
@@ -38,7 +38,9 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards {
 
 impl AddCallGuards {
     pub fn add_call_guards(&self, body: &mut Body<'_>) {
-        let pred_count: IndexVec<_, _> = body.predecessors().iter().map(|ps| ps.len()).collect();
+        let mut pred_count: IndexVec<_, _> =
+            body.predecessors().iter().map(|ps| ps.len()).collect();
+        pred_count[START_BLOCK] += 1;
 
         // We need a place to store the new blocks generated
         let mut new_blocks = Vec::new();
diff --git a/compiler/rustc_mir/src/transform/check_consts/check.rs b/compiler/rustc_mir/src/transform/check_consts/check.rs
index 48fd63b258c..09e908e6757 100644
--- a/compiler/rustc_mir/src/transform/check_consts/check.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/check.rs
@@ -420,8 +420,8 @@ impl Checker<'mir, 'tcx> {
                     ty::PredicateKind::ClosureKind(..) => {
                         bug!("closure kind predicate on function: {:#?}", predicate)
                     }
-                    ty::PredicateKind::Subtype(_) => {
-                        bug!("subtype predicate on function: {:#?}", predicate)
+                    ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
+                        bug!("subtype/coerce predicate on function: {:#?}", predicate)
                     }
                     ty::PredicateKind::Trait(pred) => {
                         if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index 6fd7d29d777..464079656f9 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -369,10 +369,10 @@ impl DebugCounters {
                     }
                     return format!("({})", self.format_counter_kind(counter_kind));
                 }
-                return self.format_counter_kind(counter_kind).to_string();
+                return self.format_counter_kind(counter_kind);
             }
         }
-        format!("#{}", operand.index().to_string())
+        format!("#{}", operand.index())
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs
index 40b1a8a2da9..03277b1b2e0 100644
--- a/compiler/rustc_mir/src/transform/remove_zsts.rs
+++ b/compiler/rustc_mir/src/transform/remove_zsts.rs
@@ -9,9 +9,6 @@ pub struct RemoveZsts;
 
 impl<'tcx> MirPass<'tcx> for RemoveZsts {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 3 {
-            return;
-        }
         let param_env = tcx.param_env(body.source.def_id());
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         for block in basic_blocks.iter_mut() {
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 13cfc3695cc..1feb8b0d7a0 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -155,12 +155,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ascription: thir::Ascription { variance, user_ty, user_ty_span },
             } => {
                 // Apply the type ascription to the value at `match_pair.place`, which is the
-                candidate.ascriptions.push(Ascription {
-                    span: user_ty_span,
-                    user_ty,
-                    source: match_pair.place.clone().into_place(self.tcx, self.typeck_results),
-                    variance,
-                });
+                if let Ok(place_resolved) =
+                    match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                {
+                    candidate.ascriptions.push(Ascription {
+                        span: user_ty_span,
+                        user_ty,
+                        source: place_resolved.into_place(self.tcx, self.typeck_results),
+                        variance,
+                    });
+                }
 
                 candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
 
@@ -173,15 +177,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
-                candidate.bindings.push(Binding {
-                    name,
-                    mutability,
-                    span: match_pair.pattern.span,
-                    source: match_pair.place.clone().into_place(self.tcx, self.typeck_results),
-                    var_id: var,
-                    var_ty: ty,
-                    binding_mode: mode,
-                });
+                if let Ok(place_resolved) =
+                    match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                {
+                    candidate.bindings.push(Binding {
+                        name,
+                        mutability,
+                        span: match_pair.pattern.span,
+                        source: place_resolved.into_place(self.tcx, self.typeck_results),
+                        var_id: var,
+                        var_ty: ty,
+                        binding_mode: mode,
+                    });
+                }
 
                 if let Some(subpattern) = subpattern.as_ref() {
                     // this is the `x @ P` case; have to keep matching against `P` now
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 3cf8ae6efd9..88dd76e37c1 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -31,15 +31,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         suffix: &'pat [Pat<'tcx>],
     ) {
         let tcx = self.tcx;
-        let (min_length, exact_size) = match place
-            .clone()
-            .into_place(tcx, self.typeck_results)
-            .ty(&self.local_decls, tcx)
-            .ty
-            .kind()
+        let (min_length, exact_size) = if let Ok(place_resolved) =
+            place.clone().try_upvars_resolved(tcx, self.typeck_results)
         {
-            ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
-            _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+            match place_resolved
+                .into_place(tcx, self.typeck_results)
+                .ty(&self.local_decls, tcx)
+                .ty
+                .kind()
+            {
+                ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+                _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+            }
+        } else {
+            ((prefix.len() + suffix.len()).try_into().unwrap(), false)
         };
 
         match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 3df8ade2169..a683cb05e16 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -11,7 +11,8 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
+use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
 use rustc_middle::bug;
@@ -354,9 +355,8 @@ trait VisibilityLike: Sized {
 
     // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
     // associated types for which we can't determine visibility precisely.
-    fn of_impl(hir_id: hir::HirId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self {
+    fn of_impl(def_id: LocalDefId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self {
         let mut find = FindMin { tcx, access_levels, min: Self::MAX };
-        let def_id = tcx.hir().local_def_id(hir_id);
         find.visit(tcx.type_of(def_id));
         if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
             find.visit_trait(trait_ref);
@@ -424,7 +424,7 @@ struct EmbargoVisitor<'tcx> {
 
 struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
     access_level: Option<AccessLevel>,
-    item_def_id: DefId,
+    item_def_id: LocalDefId,
     ev: &'a mut EmbargoVisitor<'tcx>,
 }
 
@@ -448,12 +448,12 @@ impl EmbargoVisitor<'tcx> {
 
     fn reach(
         &mut self,
-        item_id: hir::HirId,
+        def_id: LocalDefId,
         access_level: Option<AccessLevel>,
     ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
         ReachEverythingInTheInterfaceVisitor {
             access_level: cmp::min(access_level, Some(AccessLevel::Reachable)),
-            item_def_id: self.tcx.hir().local_def_id(item_id).to_def_id(),
+            item_def_id: def_id,
             ev: self,
         }
     }
@@ -536,10 +536,10 @@ impl EmbargoVisitor<'tcx> {
                     | hir::ItemKind::Union(ref struct_def, _) = item.kind
                     {
                         for field in struct_def.fields() {
-                            let field_vis =
-                                self.tcx.visibility(self.tcx.hir().local_def_id(field.hir_id));
+                            let def_id = self.tcx.hir().local_def_id(field.hir_id);
+                            let field_vis = self.tcx.visibility(def_id);
                             if field_vis.is_accessible_from(module.to_def_id(), self.tcx) {
-                                self.reach(field.hir_id, level).ty();
+                                self.reach(def_id, level).ty();
                             }
                         }
                     } else {
@@ -638,7 +638,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let inherited_item_level = match item.kind {
             hir::ItemKind::Impl { .. } => {
-                Option::<AccessLevel>::of_impl(item.hir_id(), self.tcx, &self.access_levels)
+                Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels)
             }
             // Foreign modules inherit level from parents.
             hir::ItemKind::ForeignMod { .. } => self.prev_level,
@@ -750,7 +750,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     // reachable if they are returned via `impl Trait`, even from private functions.
                     let exist_level =
                         cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
-                    self.reach(item.hir_id(), exist_level).generics().predicates().ty();
+                    self.reach(item.def_id, exist_level).generics().predicates().ty();
                 }
             }
             // Visit everything.
@@ -759,15 +759,15 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id(), item_level).generics().predicates().ty();
+                    self.reach(item.def_id, item_level).generics().predicates().ty();
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id(), item_level).generics().predicates();
+                    self.reach(item.def_id, item_level).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
-                        let mut reach = self.reach(trait_item_ref.id.hir_id(), item_level);
+                        let mut reach = self.reach(trait_item_ref.id.def_id, item_level);
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
@@ -782,18 +782,18 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::TraitAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id(), item_level).generics().predicates();
+                    self.reach(item.def_id, item_level).generics().predicates();
                 }
             }
             // Visit everything except for private impl items.
             hir::ItemKind::Impl(ref impl_) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id(), item_level).generics().predicates().ty().trait_ref();
+                    self.reach(item.def_id, item_level).generics().predicates().ty().trait_ref();
 
                     for impl_item_ref in impl_.items {
                         let impl_item_level = self.get(impl_item_ref.id.def_id);
                         if impl_item_level.is_some() {
-                            self.reach(impl_item_ref.id.hir_id(), impl_item_level)
+                            self.reach(impl_item_ref.id.def_id, impl_item_level)
                                 .generics()
                                 .predicates()
                                 .ty();
@@ -805,13 +805,14 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything, but enum variants have their own levels.
             hir::ItemKind::Enum(ref def, _) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id(), item_level).generics().predicates();
+                    self.reach(item.def_id, item_level).generics().predicates();
                 }
                 for variant in def.variants {
                     let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
                     if variant_level.is_some() {
                         for field in variant.data.fields() {
-                            self.reach(field.hir_id, variant_level).ty();
+                            self.reach(self.tcx.hir().local_def_id(field.hir_id), variant_level)
+                                .ty();
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
@@ -824,7 +825,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
                 for foreign_item in items {
                     let foreign_item_level = self.get(foreign_item.id.def_id);
                     if foreign_item_level.is_some() {
-                        self.reach(foreign_item.id.hir_id(), foreign_item_level)
+                        self.reach(foreign_item.id.def_id, foreign_item_level)
                             .generics()
                             .predicates()
                             .ty();
@@ -834,11 +835,12 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything except for private fields.
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id(), item_level).generics().predicates();
+                    self.reach(item.def_id, item_level).generics().predicates();
                     for field in struct_def.fields() {
-                        let field_level = self.get(self.tcx.hir().local_def_id(field.hir_id));
+                        let def_id = self.tcx.hir().local_def_id(field.hir_id);
+                        let field_level = self.get(def_id);
                         if field_level.is_some() {
-                            self.reach(field.hir_id, field_level).ty();
+                            self.reach(def_id, field_level).ty();
                         }
                     }
                 }
@@ -992,7 +994,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
 struct NamePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
-    current_item: Option<hir::HirId>,
+    current_item: LocalDefId,
 }
 
 impl<'tcx> NamePrivacyVisitor<'tcx> {
@@ -1014,11 +1016,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         field: &'tcx ty::FieldDef,
         in_update_syntax: bool,
     ) {
+        if def.is_enum() {
+            return;
+        }
+
         // definition of the field
         let ident = Ident::new(kw::Empty, use_ctxt);
-        let current_hir = self.current_item.unwrap();
-        let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, current_hir).1;
-        if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
+        let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item);
+        let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, hir_id).1;
+        if !field.vis.is_accessible_from(def_id, self.tcx) {
             let label = if in_update_syntax {
                 format!("field `{}` is private", field.ident)
             } else {
@@ -1063,7 +1069,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let orig_current_item = self.current_item.replace(item.hir_id());
+        let orig_current_item = mem::replace(&mut self.current_item, item.def_id);
         intravisit::walk_item(self, item);
         self.current_item = orig_current_item;
     }
@@ -1763,9 +1769,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
 
 struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    item_id: hir::HirId,
-    item_def_id: DefId,
-    span: Span,
+    item_def_id: LocalDefId,
     /// The visitor checks that each component type is at least this visible.
     required_visibility: ty::Visibility,
     has_pub_restricted: bool,
@@ -1820,8 +1824,8 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
         if self.leaks_private_dep(def_id) {
             self.tcx.struct_span_lint_hir(
                 lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
-                self.item_id,
-                self.span,
+                self.tcx.hir().local_def_id_to_hir_id(self.item_def_id),
+                self.tcx.def_span(self.item_def_id.to_def_id()),
                 |lint| {
                     lint.build(&format!(
                         "{} `{}` from private dependency '{}' in public \
@@ -1856,15 +1860,16 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
                 }
             };
             let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
+            let span = self.tcx.def_span(self.item_def_id.to_def_id());
             if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
                 let mut err = if kind == "trait" {
-                    struct_span_err!(self.tcx.sess, self.span, E0445, "{}", make_msg())
+                    struct_span_err!(self.tcx.sess, span, E0445, "{}", make_msg())
                 } else {
-                    struct_span_err!(self.tcx.sess, self.span, E0446, "{}", make_msg())
+                    struct_span_err!(self.tcx.sess, span, E0446, "{}", make_msg())
                 };
                 let vis_span =
                     self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
-                err.span_label(self.span, format!("can't leak {} {}", vis_descr, kind));
+                err.span_label(span, format!("can't leak {} {}", vis_descr, kind));
                 err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
                 err.emit();
             } else {
@@ -1872,7 +1877,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
                 self.tcx.struct_span_lint_hir(
                     lint::builtin::PRIVATE_IN_PUBLIC,
                     hir_id,
-                    self.span,
+                    span,
                     |lint| lint.build(&format!("{} (error {})", make_msg(), err_code)).emit(),
                 );
             }
@@ -1915,35 +1920,33 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
 struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     has_pub_restricted: bool,
-    old_error_set_ancestry: HirIdSet,
+    old_error_set_ancestry: LocalDefIdSet,
 }
 
 impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
     fn check(
         &self,
-        item_id: hir::HirId,
+        def_id: LocalDefId,
         required_visibility: ty::Visibility,
     ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
         SearchInterfaceForPrivateItemsVisitor {
             tcx: self.tcx,
-            item_id,
-            item_def_id: self.tcx.hir().local_def_id(item_id).to_def_id(),
-            span: self.tcx.hir().span(item_id),
+            item_def_id: def_id,
             required_visibility,
             has_pub_restricted: self.has_pub_restricted,
-            has_old_errors: self.old_error_set_ancestry.contains(&item_id),
+            has_old_errors: self.old_error_set_ancestry.contains(&def_id),
             in_assoc_ty: false,
         }
     }
 
     fn check_assoc_item(
         &self,
-        hir_id: hir::HirId,
+        def_id: LocalDefId,
         assoc_item_kind: AssocItemKind,
         defaultness: hir::Defaultness,
         vis: ty::Visibility,
     ) {
-        let mut check = self.check(hir_id, vis);
+        let mut check = self.check(def_id, vis);
 
         let (check_ty, is_assoc_ty) = match assoc_item_kind {
             AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
@@ -1982,38 +1985,38 @@ impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
-                self.check(item.hir_id(), item_visibility).generics().predicates().ty();
+                self.check(item.def_id, item_visibility).generics().predicates().ty();
             }
             hir::ItemKind::OpaqueTy(..) => {
                 // `ty()` for opaque types is the underlying type,
                 // it's not a part of interface, so we skip it.
-                self.check(item.hir_id(), item_visibility).generics().bounds();
+                self.check(item.def_id, item_visibility).generics().bounds();
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
-                self.check(item.hir_id(), item_visibility).generics().predicates();
+                self.check(item.def_id, item_visibility).generics().predicates();
 
                 for trait_item_ref in trait_item_refs {
                     self.check_assoc_item(
-                        trait_item_ref.id.hir_id(),
+                        trait_item_ref.id.def_id,
                         trait_item_ref.kind,
                         trait_item_ref.defaultness,
                         item_visibility,
                     );
 
                     if let AssocItemKind::Type = trait_item_ref.kind {
-                        self.check(trait_item_ref.id.hir_id(), item_visibility).bounds();
+                        self.check(trait_item_ref.id.def_id, item_visibility).bounds();
                     }
                 }
             }
             hir::ItemKind::TraitAlias(..) => {
-                self.check(item.hir_id(), item_visibility).generics().predicates();
+                self.check(item.def_id, item_visibility).generics().predicates();
             }
             hir::ItemKind::Enum(ref def, _) => {
-                self.check(item.hir_id(), item_visibility).generics().predicates();
+                self.check(item.def_id, item_visibility).generics().predicates();
 
                 for variant in def.variants {
                     for field in variant.data.fields() {
-                        self.check(field.hir_id, item_visibility).ty();
+                        self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility).ty();
                     }
                 }
             }
@@ -2021,16 +2024,17 @@ impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
                     let vis = tcx.visibility(foreign_item.id.def_id);
-                    self.check(foreign_item.id.hir_id(), vis).generics().predicates().ty();
+                    self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
                 }
             }
             // Subitems of structs and unions have their own publicity.
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                self.check(item.hir_id(), item_visibility).generics().predicates();
+                self.check(item.def_id, item_visibility).generics().predicates();
 
                 for field in struct_def.fields() {
-                    let field_visibility = tcx.visibility(tcx.hir().local_def_id(field.hir_id));
-                    self.check(field.hir_id, min(item_visibility, field_visibility, tcx)).ty();
+                    let def_id = tcx.hir().local_def_id(field.hir_id);
+                    let field_visibility = tcx.visibility(def_id);
+                    self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
                 }
             }
             // An inherent impl is public when its type is public
@@ -2038,8 +2042,8 @@ impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity.
             hir::ItemKind::Impl(ref impl_) => {
-                let impl_vis = ty::Visibility::of_impl(item.hir_id(), tcx, &Default::default());
-                self.check(item.hir_id(), impl_vis).generics().predicates();
+                let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
+                self.check(item.def_id, impl_vis).generics().predicates();
                 for impl_item_ref in impl_.items {
                     let impl_item_vis = if impl_.of_trait.is_none() {
                         min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
@@ -2047,7 +2051,7 @@ impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
                         impl_vis
                     };
                     self.check_assoc_item(
-                        impl_item_ref.id.hir_id(),
+                        impl_item_ref.id.def_id,
                         impl_item_ref.kind,
                         impl_item_ref.defaultness,
                         impl_item_vis,
@@ -2119,7 +2123,8 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
 
 fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     // Check privacy of names not checked in previous compilation stages.
-    let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: None };
+    let mut visitor =
+        NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id };
     let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
 
     intravisit::walk_mod(&mut visitor, module, hir_id);
@@ -2188,7 +2193,15 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
     }
 
     // Check for private types and traits in public interfaces.
-    let mut visitor =
-        PrivateItemsInPublicInterfacesVisitor { tcx, has_pub_restricted, old_error_set_ancestry };
+    let mut visitor = PrivateItemsInPublicInterfacesVisitor {
+        tcx,
+        has_pub_restricted,
+        // Only definition IDs are ever searched in `old_error_set_ancestry`,
+        // so we can filter away all non-definition IDs at this point.
+        old_error_set_ancestry: old_error_set_ancestry
+            .into_iter()
+            .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
+            .collect(),
+    };
     krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
 }
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index ace7cffd16d..38ab26d66ac 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -332,6 +332,16 @@ impl<'tcx> Key for Ty<'tcx> {
     }
 }
 
+impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 9f4f2b82f60..760b7469961 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -63,8 +63,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
     // We have information about whether `use` (import) items are actually
     // used now. If an import is not used at all, we signal a lint error.
     fn check_import(&mut self, id: ast::NodeId) {
-        let mut used = false;
-        self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
+        let used = self.r.used_imports.contains(&id);
         let def_id = self.r.local_def_id(id);
         if !used {
             if self.r.maybe_unused_trait_imports.contains(&def_id) {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 0a5da653fab..3cf04268756 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -950,9 +950,7 @@ impl<'a> Resolver<'a> {
         self.add_typo_suggestion(err, suggestion, ident.span);
 
         let import_suggestions =
-            self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, |res| {
-                matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))
-            });
+            self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
         show_candidates(err, None, &import_suggestions, false, true);
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index acfa389fed5..dfb6d89a0d1 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -303,7 +303,7 @@ impl<'a> Resolver<'a> {
                     if self.last_import_segment && check_usable(self, binding).is_err() {
                         Err((Determined, Weak::No))
                     } else {
-                        self.record_use(ident, ns, binding, restricted_shadowing);
+                        self.record_use(ident, binding, restricted_shadowing);
 
                         if let Some(shadowed_glob) = resolution.shadowed_glob {
                             // Forbid expanded shadowing to avoid time travel.
@@ -609,9 +609,9 @@ impl<'a> Resolver<'a> {
             self.per_ns(|this, ns| {
                 let key = this.new_key(target, ns);
                 let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
-                // Consider erroneous imports used to avoid duplicate diagnostics.
-                this.record_use(target, ns, dummy_binding, false);
             });
+            // Consider erroneous imports used to avoid duplicate diagnostics.
+            self.record_use(target, dummy_binding, false);
         }
     }
 }
@@ -709,7 +709,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 }
             } else if is_indeterminate {
                 // Consider erroneous imports used to avoid duplicate diagnostics.
-                self.r.used_imports.insert((import.id, TypeNS));
+                self.r.used_imports.insert(import.id);
                 let path = import_path_to_string(
                     &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
                     &import.kind,
@@ -902,7 +902,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         import.vis.set(orig_vis);
         if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
             // Consider erroneous imports used to avoid duplicate diagnostics.
-            self.r.used_imports.insert((import.id, TypeNS));
+            self.r.used_imports.insert(import.id);
         }
         let module = match path_res {
             PathResult::Module(module) => {
@@ -1043,7 +1043,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                 {
                                     this.record_use(
                                         ident,
-                                        ns,
                                         target_binding,
                                         import.module_path.is_empty(),
                                     );
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 00d291946df..0b552aa07f5 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1738,7 +1738,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // whether they can be shadowed by fresh bindings or not, so force an error.
                 // issues/33118#issuecomment-233962221 (see below) still applies here,
                 // but we have to ignore it for backward compatibility.
-                self.r.record_use(ident, ValueNS, binding, false);
+                self.r.record_use(ident, binding, false);
                 return None;
             }
             LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
@@ -1753,7 +1753,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ) if is_syntactic_ambiguity => {
                 // Disambiguate in favor of a unit struct/variant or constant pattern.
                 if let Some(binding) = binding {
-                    self.r.record_use(ident, ValueNS, binding, false);
+                    self.r.record_use(ident, binding, false);
                 }
                 Some(res)
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7114fd33188..465007507da 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -942,7 +942,7 @@ pub struct Resolver<'a> {
     glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
     /// Visibilities in "lowered" form, for all entities that have them.
     visibilities: FxHashMap<LocalDefId, ty::Visibility>,
-    used_imports: FxHashSet<(NodeId, Namespace)>,
+    used_imports: FxHashSet<NodeId>,
     maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
 
@@ -1656,7 +1656,6 @@ impl<'a> Resolver<'a> {
     fn record_use(
         &mut self,
         ident: Ident,
-        ns: Namespace,
         used_binding: &'a NameBinding<'a>,
         is_lexical_scope: bool,
     ) {
@@ -1684,9 +1683,9 @@ impl<'a> Resolver<'a> {
             }
             used.set(true);
             import.used.set(true);
-            self.used_imports.insert((import.id, ns));
+            self.used_imports.insert(import.id);
             self.add_to_glob_map(&import, ident);
-            self.record_use(ident, ns, binding, false);
+            self.record_use(ident, binding, false);
         }
     }
 
@@ -3241,7 +3240,7 @@ impl<'a> Resolver<'a> {
         self.extern_prelude.get(&ident.normalize_to_macros_2_0()).cloned().and_then(|entry| {
             if let Some(binding) = entry.extern_crate_item {
                 if !speculative && entry.introduced_by_item {
-                    self.record_use(ident, TypeNS, binding, false);
+                    self.record_use(ident, binding, false);
                 }
                 Some(binding)
             } else {
@@ -3428,7 +3427,7 @@ impl<'a> Resolver<'a> {
         let is_import = name_binding.is_import();
         let span = name_binding.span;
         if let Res::Def(DefKind::Fn, _) = res {
-            self.record_use(ident, ValueNS, name_binding, false);
+            self.record_use(ident, name_binding, false);
         }
         self.main_def = Some(MainDefinition { res, is_import, span });
     }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index b2a8aa0cecc..7f86f891c44 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1090,7 +1090,7 @@ impl<'a> Resolver<'a> {
             ) {
                 Ok(binding) => {
                     let initial_res = initial_binding.map(|initial_binding| {
-                        self.record_use(ident, MacroNS, initial_binding, false);
+                        self.record_use(ident, initial_binding, false);
                         initial_binding.res()
                     });
                     let res = binding.res();
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 1c95cc91208..9e127577b61 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -157,7 +157,7 @@ scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
 // FIXME: We should use this enum or something like it to get rid of the
 // use of magic `/rust/1.x/...` paths across the board.
 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)]
-#[derive(HashStable_Generic, Decodable)]
+#[derive(Decodable)]
 pub enum RealFileName {
     LocalPath(PathBuf),
     /// For remapped paths (namely paths into libstd that have been mapped
@@ -269,7 +269,7 @@ impl RealFileName {
 
 /// Differentiates between real files and common virtual files.
 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
-#[derive(HashStable_Generic, Decodable, Encodable)]
+#[derive(Decodable, Encodable)]
 pub enum FileName {
     Real(RealFileName),
     /// Call to `quote!`.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index e5805d9e691..6468419fce7 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -2,8 +2,15 @@ use super::apple_sdk_base::{opts, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
+    // Clang automatically chooses a more specific target based on
+    // IPHONEOS_DEPLOYMENT_TARGET.
+    // This is required for the target to pick the right
+    // MACH-O commands, so we do too.
+    let arch = "arm64";
+    let llvm_target = super::apple_base::ios_llvm_target(arch);
+
     Target {
-        llvm_target: "arm64-apple-ios".to_string(),
+        llvm_target,
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
index 09ea7d33cfd..0caecd2987b 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -6,6 +6,12 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { max_atomic_width: Some(128), ..super::freebsd_base::opts() },
+        options: TargetOptions {
+            max_atomic_width: Some(128),
+            supported_sanitizers: SanitizerSet::ADDRESS
+                | SanitizerSet::MEMORY
+                | SanitizerSet::THREAD,
+            ..super::freebsd_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 0c8a89210ff..cff0b3651e1 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -91,6 +91,11 @@ fn ios_deployment_target() -> (u32, u32) {
     deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
 }
 
+pub fn ios_llvm_target(arch: &str) -> String {
+    let (major, minor) = ios_deployment_target();
+    format!("{}-apple-ios{}.{}.0", arch, major, minor)
+}
+
 pub fn ios_sim_llvm_target(arch: &str) -> String {
     let (major, minor) = ios_deployment_target();
     format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index 559a1a40868..f10d4d49bb9 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -14,7 +14,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+        data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
         arch: "powerpc64".to_string(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index f1190b159ab..611621727bd 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".to_string(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+        data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
         arch: "powerpc64".to_string(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index 3ebc5469e0a..9c63997ce2f 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+        data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
         arch: "powerpc64".to_string(),
         options: TargetOptions { endian: Endian::Big, ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
index 76f70e474f0..f645eceadfe 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -9,7 +9,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
         pointer_width: 64,
-        data_layout: "e-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+        data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
         arch: "powerpc64".to_string(),
         options: TargetOptions { mcount: "_mcount".to_string(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
index 42c49103b3b..934371fb221 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -9,7 +9,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".to_string(),
         pointer_width: 64,
-        data_layout: "e-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+        data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
         arch: "powerpc64".to_string(),
         options: TargetOptions { mcount: "_mcount".to_string(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 302139395d3..86b1a755233 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -43,7 +43,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-unknown-emscripten".to_string(),
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20".to_string(),
         arch: "wasm32".to_string(),
         options: opts,
     }
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 834c4dbfc05..134c6803b15 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -54,7 +54,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-unknown-unknown".to_string(),
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(),
         arch: "wasm32".to_string(),
         options,
     }
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index a6b12d2ee8f..2dab206dc76 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -109,7 +109,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-wasi".to_string(),
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(),
         arch: "wasm32".to_string(),
         options,
     }
diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
index 8bfb229d77f..fb6526c0e72 100644
--- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
@@ -32,7 +32,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm64-unknown-unknown".to_string(),
         pointer_width: 64,
-        data_layout: "e-m:e-p:64:64-i64:64-n32:64-S128".to_string(),
+        data_layout: "e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20".to_string(),
         arch: "wasm64".to_string(),
         options,
     }
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 1a195ce18ec..e6686b8cc70 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -1119,6 +1119,7 @@ crate fn required_region_bounds(
                 ty::PredicateKind::Projection(..)
                 | ty::PredicateKind::Trait(..)
                 | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::WellFormed(..)
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 2f91666ca64..2c09c551b65 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -565,6 +565,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
                     }
 
+                    ty::PredicateKind::Coerce(predicate) => {
+                        // Errors for Coerce predicates show up as
+                        // `FulfillmentErrorCode::CodeSubtypeError`,
+                        // not selection error.
+                        span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
+                    }
+
                     ty::PredicateKind::RegionOutlives(predicate) => {
                         let predicate = bound_predicate.rebind(predicate);
                         let predicate = self.resolve_vars_if_possible(predicate);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 5499993db63..003642ff259 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2072,6 +2072,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ObligationCauseCode::SizedYieldType => {
                 err.note("the yield type of a generator must have a statically known size");
             }
+            ObligationCauseCode::SizedBoxType => {
+                err.note("the type of a box expression must have a statically known size");
+            }
             ObligationCauseCode::AssignmentLhsSized => {
                 err.note("the left-hand-side of an assignment must have a statically known size");
             }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 7048f0dbedc..4b94deff825 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -402,6 +402,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 | ty::PredicateKind::ObjectSafe(_)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(_)
+                | ty::PredicateKind::Coerce(_)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..) => {
                     let pred = infcx.replace_bound_vars_with_placeholders(binder);
@@ -517,6 +518,31 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                     }
                 }
 
+                ty::PredicateKind::Coerce(coerce) => {
+                    match self.selcx.infcx().coerce_predicate(
+                        &obligation.cause,
+                        obligation.param_env,
+                        Binder::dummy(coerce),
+                    ) {
+                        None => {
+                            // None means that both are unresolved.
+                            pending_obligation.stalled_on = vec![
+                                TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(),
+                                TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(),
+                            ];
+                            ProcessResult::Unchanged
+                        }
+                        Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+                        Some(Err(err)) => {
+                            let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
+                            ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
+                                expected_found,
+                                err,
+                            ))
+                        }
+                    }
+                }
+
                 ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                     match const_evaluatable::is_const_evaluatable(
                         self.selcx.infcx(),
@@ -552,11 +578,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
                             (c1.val, c2.val)
                         {
-                            if self
-                                .selcx
-                                .tcx()
-                                .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
-                            {
+                            if infcx.try_unify_abstract_consts(a, b) {
                                 return ProcessResult::Changed(vec![]);
                             }
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 585fcf795b7..477d29f1a4f 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -28,6 +28,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{
@@ -759,48 +760,38 @@ fn vtable_trait_first_method_offset<'tcx>(
 pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
     tcx: TyCtxt<'tcx>,
     key: (
-        ty::PolyTraitRef<'tcx>, // trait owning vtable
-        ty::PolyTraitRef<'tcx>, // super trait ref
+        Ty<'tcx>, // trait object type whose trait owning vtable
+        Ty<'tcx>, // trait object for supertrait
     ),
 ) -> Option<usize> {
-    let (trait_owning_vtable, super_trait_ref) = key;
-    let super_trait_did = super_trait_ref.def_id();
-    // FIXME: take substsref part into account here after upcasting coercion allows the same def_id occur
-    // multiple times.
+    let (source, target) = key;
+    assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer());
+    assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer());
 
-    let vtable_segment_callback = {
-        let mut vptr_offset = 0;
-        move |segment| {
-            match segment {
-                VtblSegment::MetadataDSA => {
-                    vptr_offset += COMMON_VTABLE_ENTRIES.len();
-                }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
-                    if trait_ref.def_id() == super_trait_did {
-                        if emit_vptr {
-                            return ControlFlow::Break(Some(vptr_offset));
-                        } else {
-                            return ControlFlow::Break(None);
-                        }
-                    }
+    // this has been typecked-before, so diagnostics is not really needed.
+    let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
 
-                    if emit_vptr {
-                        vptr_offset += 1;
-                    }
-                }
-            }
-            ControlFlow::Continue(())
-        }
+    let trait_ref = ty::TraitRef {
+        def_id: unsize_trait_did,
+        substs: tcx.mk_substs_trait(source, &[target.into()]),
     };
+    let obligation = Obligation::new(
+        ObligationCause::dummy(),
+        ty::ParamEnv::reveal_all(),
+        ty::Binder::dummy(ty::TraitPredicate { trait_ref, constness: hir::Constness::NotConst }),
+    );
 
-    if let Some(vptr_offset) =
-        prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
-    {
-        vptr_offset
-    } else {
-        bug!("Failed to find info for expected trait in vtable");
-    }
+    let implsrc = tcx.infer_ctxt().enter(|infcx| {
+        let mut selcx = SelectionContext::new(&infcx);
+        selcx.select(&obligation).unwrap()
+    });
+
+    let implsrc_traitcasting = match implsrc {
+        Some(ImplSource::TraitUpcasting(data)) => data,
+        _ => bug!(),
+    };
+
+    implsrc_traitcasting.vtable_vptr_slot
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 04bc689d511..02b43de0d16 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -308,6 +308,7 @@ fn predicate_references_self(
         | ty::PredicateKind::RegionOutlives(..)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
@@ -336,6 +337,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             }
             ty::PredicateKind::Projection(..)
             | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::RegionOutlives(..)
             | ty::PredicateKind::WellFormed(..)
             | ty::PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index d1ab9fa025e..f75f7b887a5 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1483,7 +1483,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // why we special case object types.
                 false
             }
-            super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
+            super::ImplSource::AutoImpl(..)
+            | super::ImplSource::Builtin(..)
+            | super::ImplSource::TraitUpcasting(_) => {
                 // These traits have no associated types.
                 selcx.tcx().sess.delay_span_bug(
                     obligation.cause.span,
@@ -1554,6 +1556,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
         | super::ImplSource::AutoImpl(..)
         | super::ImplSource::Param(..)
         | super::ImplSource::Builtin(..)
+        | super::ImplSource::TraitUpcasting(_)
         | super::ImplSource::TraitAlias(..) => {
             // we don't create Select candidates with this kind of resolution
             span_bug!(
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 4312cc94682..e18828fec3f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -690,19 +690,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         debug!(?source, ?target, "assemble_candidates_for_unsizing");
 
-        let may_apply = match (source.kind(), target.kind()) {
+        match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
             (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
-                // See `confirm_builtin_unsize_candidate` for more info.
+                // Upcast coercions permit several things:
+                //
+                // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
+                // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
+                // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
+                //
+                // Note that neither of the first two of these changes requires any
+                // change at runtime. The third needs to change pointer metadata at runtime.
+                //
+                // We always perform upcasting coercions when we can because of reason
+                // #2 (region bounds).
                 let auto_traits_compatible = data_b
                     .auto_traits()
                     // All of a's auto traits need to be in b's auto traits.
                     .all(|b| data_a.auto_traits().any(|a| a == b));
-                auto_traits_compatible
+                if auto_traits_compatible {
+                    let principal_def_id_a = data_a.principal_def_id();
+                    let principal_def_id_b = data_b.principal_def_id();
+                    if principal_def_id_a == principal_def_id_b {
+                        // no cyclic
+                        candidates.vec.push(BuiltinUnsizeCandidate);
+                    } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
+                        // not casual unsizing, now check whether this is trait upcasting coercion.
+                        let principal_a = data_a.principal().unwrap();
+                        let target_trait_did = principal_def_id_b.unwrap();
+                        let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
+                        for (idx, upcast_trait_ref) in
+                            util::supertraits(self.tcx(), source_trait_ref).enumerate()
+                        {
+                            if upcast_trait_ref.def_id() == target_trait_did {
+                                candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
+                            }
+                        }
+                    }
+                }
             }
 
             // `T` -> `Trait`
-            (_, &ty::Dynamic(..)) => true,
+            (_, &ty::Dynamic(..)) => {
+                candidates.vec.push(BuiltinUnsizeCandidate);
+            }
 
             // Ambiguous handling is below `T` -> `Trait`, because inference
             // variables can still implement `Unsize<Trait>` and nested
@@ -710,26 +741,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
                 debug!("assemble_candidates_for_unsizing: ambiguous");
                 candidates.ambiguous = true;
-                false
             }
 
             // `[T; n]` -> `[T]`
-            (&ty::Array(..), &ty::Slice(_)) => true,
+            (&ty::Array(..), &ty::Slice(_)) => {
+                candidates.vec.push(BuiltinUnsizeCandidate);
+            }
 
             // `Struct<T>` -> `Struct<U>`
             (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
-                def_id_a == def_id_b
+                if def_id_a == def_id_b {
+                    candidates.vec.push(BuiltinUnsizeCandidate);
+                }
             }
 
             // `(.., T)` -> `(.., U)`
-            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
+            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
+                if tys_a.len() == tys_b.len() {
+                    candidates.vec.push(BuiltinUnsizeCandidate);
+                }
+            }
 
-            _ => false,
+            _ => {}
         };
-
-        if may_apply {
-            candidates.vec.push(BuiltinUnsizeCandidate);
-        }
     }
 
     fn assemble_candidates_for_trait_alias(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 0c2099593a2..0f2f5357eb7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -26,12 +26,13 @@ use crate::traits::Normalized;
 use crate::traits::OutputTypeParameterMismatch;
 use crate::traits::Selection;
 use crate::traits::TraitNotObjectSafe;
+use crate::traits::VtblSegment;
 use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
 use crate::traits::{
     ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
     ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
     ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
-    ImplSourceUserDefinedData,
+    ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
 };
 use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
 use crate::traits::{Obligation, ObligationCause};
@@ -42,6 +43,7 @@ use super::SelectionCandidate::{self, *};
 use super::SelectionContext;
 
 use std::iter;
+use std::ops::ControlFlow;
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     #[instrument(level = "debug", skip(self))]
@@ -118,6 +120,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let data = self.confirm_builtin_unsize_candidate(obligation)?;
                 Ok(ImplSource::Builtin(data))
             }
+
+            TraitUpcastingUnsizeCandidate(idx) => {
+                let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
+                Ok(ImplSource::TraitUpcasting(data))
+            }
         }
     }
 
@@ -685,10 +692,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
     }
 
-    fn confirm_builtin_unsize_candidate(
+    fn confirm_trait_upcasting_unsize_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-    ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        idx: usize,
+    ) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
+    {
         let tcx = self.tcx();
 
         // `assemble_candidates_for_unsizing` should ensure there are no late-bound
@@ -697,62 +706,123 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
         let target = self.infcx.shallow_resolve(target);
 
-        debug!(?source, ?target, "confirm_builtin_unsize_candidate");
+        debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate");
 
         let mut nested = vec![];
+        let source_trait_ref;
+        let upcast_trait_ref;
         match (source.kind(), target.kind()) {
-            // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
+            // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
             (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
-                // Upcast coercions permit several things:
-                //
-                // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
-                // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
-                // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
-                //
-                // Note that neither of the first two of these changes requires any
-                // change at runtime. The third needs to change pointer metadata at runtime.
-                //
-                // We always perform upcasting coercions when we can because of reason
-                // #2 (region bounds).
-
+                // See `assemble_candidates_for_unsizing` for more info.
                 // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
+                let principal_a = data_a.principal().unwrap();
+                source_trait_ref = principal_a.with_self_ty(tcx, source);
+                upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
+                assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id()));
+                let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| {
+                    ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
+                        tcx, trait_ref,
+                    ))
+                });
+                let iter = Some(existential_predicate)
+                    .into_iter()
+                    .chain(
+                        data_a
+                            .projection_bounds()
+                            .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+                    )
+                    .chain(
+                        data_b
+                            .auto_traits()
+                            .map(ty::ExistentialPredicate::AutoTrait)
+                            .map(ty::Binder::dummy),
+                    );
+                let existential_predicates = tcx.mk_poly_existential_predicates(iter);
+                let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
 
-                let principal_a = data_a.principal();
-                let principal_def_id_b = data_b.principal_def_id();
-
-                let existential_predicate = if let Some(principal_a) = principal_a {
-                    let source_trait_ref = principal_a.with_self_ty(tcx, source);
-                    let target_trait_did = principal_def_id_b.ok_or_else(|| Unimplemented)?;
-                    let upcast_idx = util::supertraits(tcx, source_trait_ref)
-                        .position(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
-                        .ok_or_else(|| Unimplemented)?;
-                    // FIXME(crlf0710): This is less than ideal, for example,
-                    // if the trait is defined as `trait Foo: Bar<u32> + Bar<i32>`,
-                    // the coercion from Box<Foo> to Box<dyn Bar<_>> is actually ambiguous.
-                    // We currently make this coercion fail for now.
-                    //
-                    // see #65991 for more information.
-                    if util::supertraits(tcx, source_trait_ref)
-                        .skip(upcast_idx + 1)
-                        .any(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
-                    {
-                        return Err(Unimplemented);
+                // Require that the traits involved in this upcast are **equal**;
+                // only the **lifetime bound** is changed.
+                let InferOk { obligations, .. } = self
+                    .infcx
+                    .at(&obligation.cause, obligation.param_env)
+                    .sup(target, source_trait)
+                    .map_err(|_| Unimplemented)?;
+                nested.extend(obligations);
+
+                // Register one obligation for 'a: 'b.
+                let cause = ObligationCause::new(
+                    obligation.cause.span,
+                    obligation.cause.body_id,
+                    ObjectCastObligation(target),
+                );
+                let outlives = ty::OutlivesPredicate(r_a, r_b);
+                nested.push(Obligation::with_depth(
+                    cause,
+                    obligation.recursion_depth + 1,
+                    obligation.param_env,
+                    obligation.predicate.rebind(outlives).to_predicate(tcx),
+                ));
+            }
+            _ => bug!(),
+        };
+
+        let vtable_segment_callback = {
+            let mut vptr_offset = 0;
+            move |segment| {
+                match segment {
+                    VtblSegment::MetadataDSA => {
+                        vptr_offset += ty::COMMON_VTABLE_ENTRIES.len();
                     }
-                    let target_trait_ref =
-                        util::supertraits(tcx, source_trait_ref).nth(upcast_idx).unwrap();
-                    let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
-                        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
-                            tcx, trait_ref,
-                        ))
-                    });
-                    Some(existential_predicate)
-                } else if principal_def_id_b.is_none() {
-                    None
-                } else {
-                    return Err(Unimplemented);
-                };
+                    VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+                        vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
+                        if trait_ref == upcast_trait_ref {
+                            if emit_vptr {
+                                return ControlFlow::Break(Some(vptr_offset));
+                            } else {
+                                return ControlFlow::Break(None);
+                            }
+                        }
+
+                        if emit_vptr {
+                            vptr_offset += 1;
+                        }
+                    }
+                }
+                ControlFlow::Continue(())
+            }
+        };
+
+        let vtable_vptr_slot =
+            super::super::prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback)
+                .unwrap();
 
-                let iter = existential_predicate
+        Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
+    }
+
+    fn confirm_builtin_unsize_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        let tcx = self.tcx();
+
+        // `assemble_candidates_for_unsizing` should ensure there are no late-bound
+        // regions here. See the comment there for more details.
+        let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
+        let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+        let target = self.infcx.shallow_resolve(target);
+
+        debug!(?source, ?target, "confirm_builtin_unsize_candidate");
+
+        let mut nested = vec![];
+        match (source.kind(), target.kind()) {
+            // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
+            (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
+                // See `assemble_candidates_for_unsizing` for more info.
+                // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
+                let iter = data_a
+                    .principal()
+                    .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
                     .into_iter()
                     .chain(
                         data_a
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 38dbacbf2ae..c150b222266 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -512,6 +512,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
 
+                ty::PredicateKind::Coerce(p) => {
+                    let p = bound_predicate.rebind(p);
+                    // Does this code ever run?
+                    match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
+                        Some(Ok(InferOk { mut obligations, .. })) => {
+                            self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+                            self.evaluate_predicates_recursively(
+                                previous_stack,
+                                obligations.into_iter(),
+                            )
+                        }
+                        Some(Err(_)) => Ok(EvaluatedToErr),
+                        None => Ok(EvaluatedToAmbig),
+                    }
+                }
+
                 ty::PredicateKind::WellFormed(arg) => match wf::obligations(
                     self.infcx,
                     obligation.param_env,
@@ -608,10 +624,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
                             (c1.val, c2.val)
                         {
-                            if self
-                                .tcx()
-                                .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
-                            {
+                            if self.infcx.try_unify_abstract_consts(a, b) {
                                 return Ok(EvaluatedToOk);
                             }
                         }
@@ -1500,6 +1513,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | FnPointerCandidate
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
+                | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { .. }
                 | TraitAliasCandidate(..)
                 | ObjectCandidate(_)
@@ -1517,6 +1531,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | FnPointerCandidate
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
+                | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { has_nested: true }
                 | TraitAliasCandidate(..),
                 ParamCandidate(ref cand),
@@ -1546,6 +1561,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | FnPointerCandidate
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
+                | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { .. }
                 | TraitAliasCandidate(..),
             ) => true,
@@ -1557,6 +1573,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | FnPointerCandidate
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
+                | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { .. }
                 | TraitAliasCandidate(..),
                 ObjectCandidate(_) | ProjectionCandidate(_),
@@ -1566,12 +1583,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // See if we can toss out `victim` based on specialization.
                 // This requires us to know *for sure* that the `other` impl applies
                 // i.e., `EvaluatedToOk`.
+                //
+                // FIXME(@lcnr): Using `modulo_regions` here seems kind of scary
+                // to me but is required for `std` to compile, so I didn't change it
+                // for now.
+                let tcx = self.tcx();
                 if other.evaluation.must_apply_modulo_regions() {
-                    let tcx = self.tcx();
                     if tcx.specializes((other_def, victim_def)) {
                         return true;
                     }
-                    return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+                }
+
+                if other.evaluation.must_apply_considering_regions() {
+                    match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
                         Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
                             // Subtle: If the predicate we are evaluating has inference
                             // variables, do *not* allow discarding candidates due to
@@ -1616,7 +1640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         }
                         Some(_) => true,
                         None => false,
-                    };
+                    }
                 } else {
                     false
                 }
@@ -1630,6 +1654,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | FnPointerCandidate
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
+                | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { has_nested: true }
                 | TraitAliasCandidate(..),
                 ImplCandidate(_)
@@ -1638,6 +1663,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | FnPointerCandidate
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
+                | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { has_nested: true }
                 | TraitAliasCandidate(..),
             ) => false,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 9c9664d7b5e..afef784b4c6 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -128,6 +128,10 @@ pub fn predicate_obligations<'a, 'tcx>(
             wf.compute(a.into());
             wf.compute(b.into());
         }
+        ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+            wf.compute(a.into());
+            wf.compute(b.into());
+        }
         ty::PredicateKind::ConstEvaluatable(def, substs) => {
             let obligations = wf.nominal_obligations(def.did, substs);
             wf.out.extend(obligations);
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 974755e9e26..330fd497fa1 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -109,6 +109,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
             };
@@ -193,6 +194,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             // some of these in terms of chalk operations.
             ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
@@ -592,6 +594,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@@ -719,6 +722,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 90ba90259c3..1d10d068490 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -99,6 +99,7 @@ fn compute_implied_outlives_bounds<'tcx>(
                 Some(pred) => match pred {
                     ty::PredicateKind::Trait(..)
                     | ty::PredicateKind::Subtype(..)
+                    | ty::PredicateKind::Coerce(..)
                     | ty::PredicateKind::Projection(..)
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 5ad0684fe6e..61ab5e28b67 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -65,6 +65,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 469ac04e545..4c03abb38ca 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -381,7 +381,8 @@ fn resolve_associated_item<'tcx>(
         | traits::ImplSource::Param(..)
         | traits::ImplSource::TraitAlias(..)
         | traits::ImplSource::DiscriminantKind(..)
-        | traits::ImplSource::Pointee(..) => None,
+        | traits::ImplSource::Pointee(..)
+        | traits::ImplSource::TraitUpcasting(_) => None,
     })
 }
 
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 8eb51b977ed..aae9518ad51 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1413,15 +1413,17 @@ fn check_enum<'tcx>(
                 Some(ref expr) => tcx.hir().span(expr.hir_id),
                 None => v.span,
             };
+            let display_discr = display_discriminant_value(tcx, v, discr.val);
+            let display_discr_i = display_discriminant_value(tcx, variant_i, disr_vals[i].val);
             struct_span_err!(
                 tcx.sess,
                 span,
                 E0081,
                 "discriminant value `{}` already exists",
-                disr_vals[i]
+                discr.val,
             )
-            .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
-            .span_label(span, format!("enum already has `{}`", disr_vals[i]))
+            .span_label(i_span, format!("first use of {}", display_discr_i))
+            .span_label(span, format!("enum already has {}", display_discr))
             .emit();
         }
         disr_vals.push(discr);
@@ -1431,6 +1433,25 @@ fn check_enum<'tcx>(
     check_transparent(tcx, sp, def);
 }
 
+/// Format an enum discriminant value for use in a diagnostic message.
+fn display_discriminant_value<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    variant: &hir::Variant<'_>,
+    evaluated: u128,
+) -> String {
+    if let Some(expr) = &variant.disr_expr {
+        let body = &tcx.hir().body(expr.body).value;
+        if let hir::ExprKind::Lit(lit) = &body.kind {
+            if let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node {
+                if evaluated != *lit_value {
+                    return format!("`{}` (overflowed from `{}`)", evaluated, lit_value);
+                }
+            }
+        }
+    }
+    format!("`{}`", evaluated)
+}
+
 pub(super) fn check_type_params_are_used<'tcx>(
     tcx: TyCtxt<'tcx>,
     generics: &ty::Generics,
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 208eb27c844..0b4df8e6d3c 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -42,6 +42,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
+use rustc_infer::traits::Obligation;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -50,7 +51,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{self, BytePos, Span};
@@ -146,7 +147,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
     }
 
     fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
+        // First, remove any resolved type variables (at the top level, at least):
         let a = self.shallow_resolve(a);
+        let b = self.shallow_resolve(b);
         debug!("Coerce.tys({:?} => {:?})", a, b);
 
         // Just ignore error types.
@@ -154,6 +157,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             return success(vec![], self.fcx.tcx.ty_error(), vec![]);
         }
 
+        // Coercing from `!` to any type is allowed:
         if a.is_never() {
             // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
             // type variable, we want `?T` to fallback to `!` if not
@@ -162,20 +166,26 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             //     let _: Option<?T> = Some({ return; });
             //
             // here, we would coerce from `!` to `?T`.
-            let b = self.shallow_resolve(b);
-            return if self.shallow_resolve(b).is_ty_var() {
+            return if b.is_ty_var() {
                 // Micro-optimization: no need for this if `b` is
                 // already resolved in some way.
                 let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::AdjustmentType,
                     span: self.cause.span,
                 });
-                self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
+                self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny))
             } else {
                 success(simple(Adjust::NeverToAny)(b), b, vec![])
             };
         }
 
+        // Coercing *from* an unresolved inference variable means that
+        // we have no information about the source type. This will always
+        // ultimately fall back to some form of subtyping.
+        if a.is_ty_var() {
+            return self.coerce_from_inference_variable(a, b, identity);
+        }
+
         // Consider coercing the subtype to a DST
         //
         // NOTE: this is wrapped in a `commit_if_ok` because it creates
@@ -196,9 +206,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         debug!("coerce: unsize failed");
 
         // Examine the supertype and consider auto-borrowing.
-        //
-        // Note: does not attempt to resolve type variables we encounter.
-        // See above for details.
         match *b.kind() {
             ty::RawPtr(mt_b) => {
                 return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
@@ -236,6 +243,58 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         }
     }
 
+    /// Coercing *from* an inference variable. In this case, we have no information
+    /// about the source type, so we can't really do a true coercion and we always
+    /// fall back to subtyping (`unify_and`).
+    fn coerce_from_inference_variable(
+        &self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
+    ) -> CoerceResult<'tcx> {
+        debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
+        assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a);
+        assert!(self.infcx.shallow_resolve(b) == b);
+
+        if b.is_ty_var() {
+            // Two unresolved type variables: create a `Coerce` predicate.
+            let target_ty = if self.use_lub {
+                self.infcx.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::LatticeVariable,
+                    span: self.cause.span,
+                })
+            } else {
+                b
+            };
+
+            let mut obligations = Vec::with_capacity(2);
+            for &source_ty in &[a, b] {
+                if source_ty != target_ty {
+                    obligations.push(Obligation::new(
+                        self.cause.clone(),
+                        self.param_env,
+                        ty::PredicateKind::Coerce(ty::CoercePredicate {
+                            a: source_ty,
+                            b: target_ty,
+                        })
+                        .to_predicate(self.tcx()),
+                    ));
+                }
+            }
+
+            debug!(
+                "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
+                target_ty, obligations
+            );
+            let adjustments = make_adjustments(target_ty);
+            InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
+        } else {
+            // One unresolved type variable: just apply subtyping, we may be able
+            // to do something useful.
+            self.unify_and(a, b, make_adjustments)
+        }
+    }
+
     /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
     /// To match `A` with `B`, autoderef will be performed,
     /// calling `deref`/`deref_mut` where necessary.
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 316a097556a..8d5bf98be99 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -708,11 +708,7 @@ fn compare_number_of_method_arguments<'tcx>(
                         Some(if pos == 0 {
                             arg.span
                         } else {
-                            Span::new(
-                                trait_m_sig.decl.inputs[0].span.lo(),
-                                arg.span.hi(),
-                                arg.span.ctxt(),
-                            )
+                            arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
                         })
                     } else {
                         trait_item_span
@@ -731,11 +727,7 @@ fn compare_number_of_method_arguments<'tcx>(
                     if pos == 0 {
                         arg.span
                     } else {
-                        Span::new(
-                            impl_m_sig.decl.inputs[0].span.lo(),
-                            arg.span.hi(),
-                            arg.span.ctxt(),
-                        )
+                        arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
                     }
                 } else {
                     impl_m_span
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 23ce4275d40..9cbd3f7bb33 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -313,6 +313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => NoExpectation,
         });
         let referent_ty = self.check_expr_with_expectation(expr, expected_inner);
+        self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType);
         self.tcx.mk_box(referent_ty)
     }
 
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
new file mode 100644
index 00000000000..69a8970ae09
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -0,0 +1,157 @@
+use crate::check::FnCtxt;
+use rustc_infer::infer::type_variable::Diverging;
+use rustc_middle::ty::{self, Ty};
+
+impl<'tcx> FnCtxt<'_, 'tcx> {
+    pub(super) fn type_inference_fallback(&self) {
+        // All type checking constraints were added, try to fallback unsolved variables.
+        self.select_obligations_where_possible(false, |_| {});
+        let mut fallback_has_occurred = false;
+
+        // We do fallback in two passes, to try to generate
+        // better error messages.
+        // The first time, we do *not* replace opaque types.
+        for ty in &self.unsolved_variables() {
+            debug!("unsolved_variable = {:?}", ty);
+            fallback_has_occurred |= self.fallback_if_possible(ty);
+        }
+
+        // We now see if we can make progress. This might
+        // cause us to unify inference variables for opaque types,
+        // since we may have unified some other type variables
+        // during the first phase of fallback.
+        // This means that we only replace inference variables with their underlying
+        // opaque types as a last resort.
+        //
+        // In code like this:
+        //
+        // ```rust
+        // type MyType = impl Copy;
+        // fn produce() -> MyType { true }
+        // fn bad_produce() -> MyType { panic!() }
+        // ```
+        //
+        // we want to unify the opaque inference variable in `bad_produce`
+        // with the diverging fallback for `panic!` (e.g. `()` or `!`).
+        // This will produce a nice error message about conflicting concrete
+        // types for `MyType`.
+        //
+        // If we had tried to fallback the opaque inference variable to `MyType`,
+        // we will generate a confusing type-check error that does not explicitly
+        // refer to opaque types.
+        self.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+        // We now run fallback again, but this time we allow it to replace
+        // unconstrained opaque type variables, in addition to performing
+        // other kinds of fallback.
+        for ty in &self.unsolved_variables() {
+            fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
+        }
+
+        // See if we can make any more progress.
+        self.select_obligations_where_possible(fallback_has_occurred, |_| {});
+    }
+
+    // Tries to apply a fallback to `ty` if it is an unsolved variable.
+    //
+    // - Unconstrained ints are replaced with `i32`.
+    //
+    // - Unconstrained floats are replaced with with `f64`.
+    //
+    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
+    //   is enabled. Otherwise, they are replaced with `()`.
+    //
+    // Fallback becomes very dubious if we have encountered type-checking errors.
+    // In that case, fallback to Error.
+    // The return value indicates whether fallback has occurred.
+    fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
+        // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
+        // is an unsolved variable, and we determine its fallback based
+        // solely on how it was created, not what other type variables
+        // it may have been unified with since then.
+        //
+        // The reason this matters is that other attempts at fallback may
+        // (in principle) conflict with this fallback, and we wish to generate
+        // a type error in that case. (However, this actually isn't true right now,
+        // because we're only using the builtin fallback rules. This would be
+        // true if we were using user-supplied fallbacks. But it's still useful
+        // to write the code to detect bugs.)
+        //
+        // (Note though that if we have a general type variable `?T` that is then unified
+        // with an integer type variable `?I` that ultimately never gets
+        // resolved to a special integral type, `?T` is not considered unsolved,
+        // but `?I` is. The same is true for float variables.)
+        let fallback = match ty.kind() {
+            _ if self.is_tainted_by_errors() => self.tcx.ty_error(),
+            ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
+            ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
+            _ => match self.type_var_diverges(ty) {
+                Diverging::Diverges => self.tcx.mk_diverging_default(),
+                Diverging::NotDiverging => return false,
+            },
+        };
+        debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
+
+        let span = self
+            .infcx
+            .type_var_origin(ty)
+            .map(|origin| origin.span)
+            .unwrap_or(rustc_span::DUMMY_SP);
+        self.demand_eqtype(span, ty, fallback);
+        true
+    }
+
+    /// Second round of fallback: Unconstrained type variables
+    /// created from the instantiation of an opaque
+    /// type fall back to the opaque type itself. This is a
+    /// somewhat incomplete attempt to manage "identity passthrough"
+    /// for `impl Trait` types.
+    ///
+    /// For example, in this code:
+    ///
+    ///```
+    /// type MyType = impl Copy;
+    /// fn defining_use() -> MyType { true }
+    /// fn other_use() -> MyType { defining_use() }
+    /// ```
+    ///
+    /// `defining_use` will constrain the instantiated inference
+    /// variable to `bool`, while `other_use` will constrain
+    /// the instantiated inference variable to `MyType`.
+    ///
+    /// When we process opaque types during writeback, we
+    /// will handle cases like `other_use`, and not count
+    /// them as defining usages
+    ///
+    /// However, we also need to handle cases like this:
+    ///
+    /// ```rust
+    /// pub type Foo = impl Copy;
+    /// fn produce() -> Option<Foo> {
+    ///     None
+    ///  }
+    ///  ```
+    ///
+    /// In the above snippet, the inference variable created by
+    /// instantiating `Option<Foo>` will be completely unconstrained.
+    /// We treat this as a non-defining use by making the inference
+    /// variable fall back to the opaque type itself.
+    fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
+        let span = self
+            .infcx
+            .type_var_origin(ty)
+            .map(|origin| origin.span)
+            .unwrap_or(rustc_span::DUMMY_SP);
+        let oty = self.inner.borrow().opaque_types_vars.get(ty).map(|v| *v);
+        if let Some(opaque_ty) = oty {
+            debug!(
+                "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
+                ty, opaque_ty
+            );
+            self.demand_eqtype(span, ty, opaque_ty);
+            true
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index c13901ae8be..bb80f0879a4 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -4,7 +4,7 @@ use crate::astconv::{
 };
 use crate::check::callee::{self, DeferredCallResolution};
 use crate::check::method::{self, MethodCallee, SelfSource};
-use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy};
+use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
 
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::captures::Captures;
@@ -635,83 +635,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    // Tries to apply a fallback to `ty` if it is an unsolved variable.
-    //
-    // - Unconstrained ints are replaced with `i32`.
-    //
-    // - Unconstrained floats are replaced with with `f64`.
-    //
-    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
-    //   is enabled. Otherwise, they are replaced with `()`.
-    //
-    // Fallback becomes very dubious if we have encountered type-checking errors.
-    // In that case, fallback to Error.
-    // The return value indicates whether fallback has occurred.
-    pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
-        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
-        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
-
-        assert!(ty.is_ty_infer());
-        let fallback = match self.type_is_unconstrained_numeric(ty) {
-            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
-            UnconstrainedInt => self.tcx.types.i32,
-            UnconstrainedFloat => self.tcx.types.f64,
-            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
-            Neither => {
-                // This type variable was created from the instantiation of an opaque
-                // type. The fact that we're attempting to perform fallback for it
-                // means that the function neither constrained it to a concrete
-                // type, nor to the opaque type itself.
-                //
-                // For example, in this code:
-                //
-                //```
-                // type MyType = impl Copy;
-                // fn defining_use() -> MyType { true }
-                // fn other_use() -> MyType { defining_use() }
-                // ```
-                //
-                // `defining_use` will constrain the instantiated inference
-                // variable to `bool`, while `other_use` will constrain
-                // the instantiated inference variable to `MyType`.
-                //
-                // When we process opaque types during writeback, we
-                // will handle cases like `other_use`, and not count
-                // them as defining usages
-                //
-                // However, we also need to handle cases like this:
-                //
-                // ```rust
-                // pub type Foo = impl Copy;
-                // fn produce() -> Option<Foo> {
-                //     None
-                //  }
-                //  ```
-                //
-                // In the above snippet, the inference variable created by
-                // instantiating `Option<Foo>` will be completely unconstrained.
-                // We treat this as a non-defining use by making the inference
-                // variable fall back to the opaque type itself.
-                if let FallbackMode::All = mode {
-                    if let Some(opaque_ty) = self.infcx.inner.borrow().opaque_types_vars.get(ty) {
-                        debug!(
-                            "fallback_if_possible: falling back opaque type var {:?} to {:?}",
-                            ty, opaque_ty
-                        );
-                        *opaque_ty
-                    } else {
-                        return false;
-                    }
-                } else {
-                    return false;
-                }
-            }
-        };
-        debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
-        self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
-        true
-    }
-
     pub(in super::super) fn select_all_obligations_or_error(&self) {
         debug!("select_all_obligations_or_error");
         if let Err(errors) = self
@@ -807,6 +730,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
                     }
                     ty::PredicateKind::Subtype(..) => None,
+                    ty::PredicateKind::Coerce(..) => None,
                     ty::PredicateKind::RegionOutlives(..) => None,
                     ty::PredicateKind::TypeOutlives(..) => None,
                     ty::PredicateKind::WellFormed(..) => None,
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index 9e3292d7821..b5bc9d3599a 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Get the number of generics the self type has (if an Adt) unless we can determine that
                 // the user has written the self type with generics already which we (naively) do by looking
                 // for a "<" in `self_ty_name`.
-                Adt(def, _) if !self_ty_name.contains("<") => self.tcx.generics_of(def.did).count(),
+                Adt(def, _) if !self_ty_name.contains('<') => self.tcx.generics_of(def.did).count(),
                 _ => 0,
             };
             let self_ty_generics = if self_ty_generics_count > 0 {
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index c6e6c8c5d70..486e4d15d65 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -841,6 +841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     }
                 }
                 ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::Projection(..)
                 | ty::PredicateKind::RegionOutlives(..)
                 | ty::PredicateKind::WellFormed(..)
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index d1e583ed184..ad7e96e2833 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -75,6 +75,7 @@ mod diverges;
 pub mod dropck;
 mod expectation;
 mod expr;
+mod fallback;
 mod fn_ctxt;
 mod gather_locals;
 mod generator_interior;
@@ -445,50 +446,7 @@ fn typeck_with_fallback<'tcx>(
             fcx
         };
 
-        // All type checking constraints were added, try to fallback unsolved variables.
-        fcx.select_obligations_where_possible(false, |_| {});
-        let mut fallback_has_occurred = false;
-
-        // We do fallback in two passes, to try to generate
-        // better error messages.
-        // The first time, we do *not* replace opaque types.
-        for ty in &fcx.unsolved_variables() {
-            fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque);
-        }
-        // We now see if we can make progress. This might
-        // cause us to unify inference variables for opaque types,
-        // since we may have unified some other type variables
-        // during the first phase of fallback.
-        // This means that we only replace inference variables with their underlying
-        // opaque types as a last resort.
-        //
-        // In code like this:
-        //
-        // ```rust
-        // type MyType = impl Copy;
-        // fn produce() -> MyType { true }
-        // fn bad_produce() -> MyType { panic!() }
-        // ```
-        //
-        // we want to unify the opaque inference variable in `bad_produce`
-        // with the diverging fallback for `panic!` (e.g. `()` or `!`).
-        // This will produce a nice error message about conflicting concrete
-        // types for `MyType`.
-        //
-        // If we had tried to fallback the opaque inference variable to `MyType`,
-        // we will generate a confusing type-check error that does not explicitly
-        // refer to opaque types.
-        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
-        // We now run fallback again, but this time we allow it to replace
-        // unconstrained opaque type variables, in addition to performing
-        // other kinds of fallback.
-        for ty in &fcx.unsolved_variables() {
-            fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All);
-        }
-
-        // See if we can make any more progress.
-        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+        fcx.type_inference_fallback();
 
         // Even though coercion casts provide type hints, we check casts after fallback for
         // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
@@ -914,16 +872,6 @@ enum TupleArgumentsFlag {
     TupleArguments,
 }
 
-/// Controls how we perform fallback for unconstrained
-/// type variables.
-enum FallbackMode {
-    /// Do not fallback type variables to opaque types.
-    NoOpaque,
-    /// Perform all possible kinds of fallback, including
-    /// turning type variables to opaque types.
-    All,
-}
-
 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
 #[derive(Copy, Clone)]
 struct MaybeInProgressTables<'a, 'tcx> {
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index f039790eca1..1c36335be81 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -222,8 +222,8 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
                                 let id_to_set = *ids.iter().min().unwrap();
 
                                 // Sort the id list so that the algorithm is deterministic
-                                let mut ids = ids.into_iter().collect::<SmallVec<[_; 8]>>();
-                                ids.sort();
+                                let mut ids = ids.into_iter().collect::<SmallVec<[usize; 8]>>();
+                                ids.sort_unstable();
 
                                 let mut region = connected_regions.remove(&id_to_set).unwrap();
                                 region.idents.extend_from_slice(&idents_to_add);
@@ -266,8 +266,8 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
                     // for each pair of impl blocks in the same connected region.
                     for (_id, region) in connected_regions.into_iter() {
                         let mut impl_blocks =
-                            region.impl_blocks.into_iter().collect::<SmallVec<[_; 8]>>();
-                        impl_blocks.sort();
+                            region.impl_blocks.into_iter().collect::<SmallVec<[usize; 8]>>();
+                        impl_blocks.sort_unstable();
                         for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
                             let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
                             for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 3b241317aa3..b0c95939bb7 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -269,6 +269,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                                     if def.variants.len() > 1 {
                                         needs_to_be_read = true;
                                     }
+                                } else {
+                                    // If it is not ty::Adt, then it should be read
+                                    needs_to_be_read = true;
                                 }
                             }
                             PatKind::Lit(_) | PatKind::Range(..) => {
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index d5d81603fc5..e148370a036 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -407,6 +407,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::Projection(_)
         | ty::PredicateKind::WellFormed(_)
         | ty::PredicateKind::Subtype(_)
+        | ty::PredicateKind::Coerce(_)
         | ty::PredicateKind::ObjectSafe(_)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::ConstEvaluatable(..)
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs
index 6e5be87928d..2ac1a18cffa 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_typeck/src/outlives/explicit.rs
@@ -56,6 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::Subtype(..)
+                    | ty::PredicateKind::Coerce(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
                     | ty::PredicateKind::ConstEquate(..)
                     | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 9a2205420a1..e4b28204158 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2129,16 +2129,32 @@ impl<T, A: Allocator> VecDeque<T, A> {
         F: FnMut(&T) -> bool,
     {
         let len = self.len();
-        let mut del = 0;
-        for i in 0..len {
-            if !f(&self[i]) {
-                del += 1;
-            } else if del > 0 {
-                self.swap(i - del, i);
+        let mut idx = 0;
+        let mut cur = 0;
+
+        // Stage 1: All values are retained.
+        while cur < len {
+            if !f(&self[cur]) {
+                cur += 1;
+                break;
             }
+            cur += 1;
+            idx += 1;
         }
-        if del > 0 {
-            self.truncate(len - del);
+        // Stage 2: Swap retained value into current idx.
+        while cur < len {
+            if !f(&self[cur]) {
+                cur += 1;
+                continue;
+            }
+
+            self.swap(idx, cur);
+            cur += 1;
+            idx += 1;
+        }
+        // Stage 3: Trancate all values after idx.
+        if cur != idx {
+            self.truncate(idx);
         }
     }
 
diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs
index 6116cfe1d01..56257e43462 100644
--- a/library/alloc/src/collections/vec_deque/tests.rs
+++ b/library/alloc/src/collections/vec_deque/tests.rs
@@ -42,6 +42,39 @@ fn bench_pop_back_100(b: &mut test::Bencher) {
 
 #[bench]
 #[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
+fn bench_retain_whole_10000(b: &mut test::Bencher) {
+    let v = (1..100000).collect::<VecDeque<u32>>();
+
+    b.iter(|| {
+        let mut v = v.clone();
+        v.retain(|x| *x > 0)
+    })
+}
+
+#[bench]
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
+fn bench_retain_odd_10000(b: &mut test::Bencher) {
+    let v = (1..100000).collect::<VecDeque<u32>>();
+
+    b.iter(|| {
+        let mut v = v.clone();
+        v.retain(|x| x & 1 == 0)
+    })
+}
+
+#[bench]
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
+fn bench_retain_half_10000(b: &mut test::Bencher) {
+    let v = (1..100000).collect::<VecDeque<u32>>();
+
+    b.iter(|| {
+        let mut v = v.clone();
+        v.retain(|x| *x > 50000)
+    })
+}
+
+#[bench]
+#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_pop_front_100(b: &mut test::Bencher) {
     let mut deq = VecDeque::<i32>::with_capacity(101);
 
diff --git a/library/backtrace b/library/backtrace
-Subproject 221483ebaf45df5c956adffee2d4024e7c3b96b
+Subproject 4f925f8d81dfa57067537217e501e1dff743349
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index aa91346851f..56fad602cf9 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -374,16 +374,18 @@ where
     /// # Examples
     /// ```
     /// let mut tuple = (vec![0], vec![1]);
-    /// tuple.extend(vec![(2, 3), (4, 5), (6, 7)]);
-    /// assert_eq!(tuple.0, vec![0, 2, 4, 6]);
-    /// assert_eq!(tuple.1, vec![1, 3, 5, 7]);
+    /// tuple.extend([(2, 3), (4, 5), (6, 7)]);
+    /// assert_eq!(tuple.0, [0, 2, 4, 6]);
+    /// assert_eq!(tuple.1, [1, 3, 5, 7]);
     ///
-    /// // also allows for arbitrarily nested tuples
-    /// let mut nested_tuple = (vec![(1, -1)], vec![(2, -2)]);
-    /// nested_tuple.extend(vec![((3, -3), (4, -4)), ((5, -5), (6, -6))]);
+    /// // also allows for arbitrarily nested tuples as elements
+    /// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
+    /// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
     ///
-    /// assert_eq!(nested_tuple.0, vec![(1, -1), (3, -3), (5, -5)]);
-    /// assert_eq!(nested_tuple.1, vec![(2, -2), (4, -4), (6, -6)]);
+    /// let (a, (b, c)) = nested_tuple;
+    /// assert_eq!(a, [1, 4, 7]);
+    /// assert_eq!(b, [2, 5, 8]);
+    /// assert_eq!(c, [3, 6, 9]);
     /// ```
     fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) {
         let (a, b) = self;
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 7e260aaa428..38291b3f57e 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -23,11 +23,11 @@ hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep
 std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
 
 # Dependencies of the `backtrace` crate
-addr2line = { version = "0.14.0", optional = true, default-features = false }
+addr2line = { version = "0.16.0", optional = true, default-features = false }
 rustc-demangle = { version = "0.1.18", features = ['rustc-dep-of-std'] }
 miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
 [dependencies.object]
-version = "0.22"
+version = "0.26.1"
 optional = true
 default-features = false
 features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 2c04481c04e..bdb172907ff 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -587,6 +587,12 @@ impl File {
     }
 }
 
+// In addition to the `impl`s here, `File` also has `impl`s for
+// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
+// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
+// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
+// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
+
 impl AsInner<fs_imp::File> for File {
     fn as_inner(&self) -> &fs_imp::File {
         &self.inner
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 325acf0b979..336891ec1eb 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -546,6 +546,12 @@ impl TcpStream {
     }
 }
 
+// In addition to the `impl`s here, `TcpStream` also has `impl`s for
+// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
+// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
+// `AsSocket`/`From<OwnedSocket>`/`Into<OwnedSocket>` and
+// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows.
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Read for TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -767,17 +773,24 @@ impl TcpListener {
     /// # Examples
     ///
     /// ```no_run
-    /// use std::net::TcpListener;
+    /// use std::net::{TcpListener, TcpStream};
     ///
-    /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+    /// fn handle_connection(stream: TcpStream) {
+    ///    //...
+    /// }
     ///
-    /// for stream in listener.incoming() {
-    ///     match stream {
-    ///         Ok(stream) => {
-    ///             println!("new client!");
+    /// fn main() -> std::io::Result<()> {
+    ///     let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+    ///
+    ///     for stream in listener.incoming() {
+    ///         match stream {
+    ///             Ok(stream) => {
+    ///                 handle_connection(stream);
+    ///             }
+    ///             Err(e) => { /* connection failed */ }
     ///         }
-    ///         Err(e) => { /* connection failed */ }
     ///     }
+    ///     Ok(())
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -908,6 +921,12 @@ impl TcpListener {
     }
 }
 
+// In addition to the `impl`s here, `TcpListener` also has `impl`s for
+// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
+// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
+// `AsSocket`/`From<OwnedSocket>`/`Into<OwnedSocket>` and
+// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows.
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Iterator for Incoming<'a> {
     type Item = io::Result<TcpStream>;
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index d2088a12b2c..871505843af 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -779,6 +779,12 @@ impl UdpSocket {
     }
 }
 
+// In addition to the `impl`s here, `UdpSocket` also has `impl`s for
+// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
+// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
+// `AsSocket`/`From<OwnedSocket>`/`Into<OwnedSocket>` and
+// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows.
+
 impl AsInner<net_imp::UdpSocket> for UdpSocket {
     fn as_inner(&self) -> &net_imp::UdpSocket {
         &self.0
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index fbed3d32d45..a51113dd9e7 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -2,7 +2,6 @@ use crate::io::ErrorKind;
 use crate::net::test::{next_test_ip4, next_test_ip6};
 use crate::net::*;
 use crate::sync::mpsc::channel;
-use crate::sys_common::AsInner;
 use crate::thread;
 use crate::time::{Duration, Instant};
 
@@ -173,7 +172,7 @@ fn debug() {
     let socket_addr = next_test_ip4();
 
     let udpsock = t!(UdpSocket::bind(&socket_addr));
-    let udpsock_inner = udpsock.0.socket().as_inner();
+    let udpsock_inner = udpsock.0.socket().as_raw();
     let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner);
     assert_eq!(format!("{:?}", udpsock), compare);
 }
diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs
new file mode 100644
index 00000000000..df11dc21aa7
--- /dev/null
+++ b/library/std/src/os/fd/mod.rs
@@ -0,0 +1,13 @@
+//! Owned and borrowed Unix-like file descriptors.
+
+#![unstable(feature = "io_safety", issue = "87074")]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+// `RawFd`, `AsRawFd`, etc.
+pub mod raw;
+
+// `OwnedFd`, `AsFd`, etc.
+pub mod owned;
+
+// Implementations for `AsRawFd` etc. for network types.
+mod net;
diff --git a/library/std/src/os/unix/net/raw_fd.rs b/library/std/src/os/fd/net.rs
index b3f12844101..843f45f7f5f 100644
--- a/library/std/src/os/unix/net/raw_fd.rs
+++ b/library/std/src/os/fd/net.rs
@@ -1,4 +1,5 @@
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::os::fd::owned::OwnedFd;
+use crate::os::fd::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys_common::{self, AsInner, FromInner, IntoInner};
 use crate::{net, sys};
 
@@ -8,7 +9,7 @@ macro_rules! impl_as_raw_fd {
         impl AsRawFd for net::$t {
             #[inline]
             fn as_raw_fd(&self) -> RawFd {
-                *self.as_inner().socket().as_inner()
+                self.as_inner().socket().as_raw_fd()
             }
         }
     )*};
@@ -21,8 +22,10 @@ macro_rules! impl_from_raw_fd {
         impl FromRawFd for net::$t {
             #[inline]
             unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
-                let socket = sys::net::Socket::from_inner(fd);
-                net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+                unsafe {
+                    let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
+                    net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+                }
             }
         }
     )*};
@@ -35,7 +38,7 @@ macro_rules! impl_into_raw_fd {
         impl IntoRawFd for net::$t {
             #[inline]
             fn into_raw_fd(self) -> RawFd {
-                self.into_inner().into_socket().into_inner()
+                self.into_inner().into_socket().into_inner().into_inner().into_raw_fd()
             }
         }
     )*};
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
new file mode 100644
index 00000000000..52d7d4690d3
--- /dev/null
+++ b/library/std/src/os/fd/owned.rs
@@ -0,0 +1,289 @@
+//! Owned and borrowed Unix-like file descriptors.
+
+#![unstable(feature = "io_safety", issue = "87074")]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::fmt;
+use crate::fs;
+use crate::marker::PhantomData;
+use crate::mem::forget;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// A borrowed file descriptor.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the file descriptor.
+///
+/// This uses `repr(transparent)` and has the representation of a host file
+/// descriptor, so it can be used in FFI in places where a file descriptor is
+/// passed as an argument, it is not captured or consumed, and it never has the
+/// value `-1`.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[unstable(feature = "io_safety", issue = "87074")]
+pub struct BorrowedFd<'fd> {
+    fd: RawFd,
+    _phantom: PhantomData<&'fd OwnedFd>,
+}
+
+/// An owned file descriptor.
+///
+/// This closes the file descriptor on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host file
+/// descriptor, so it can be used in FFI in places where a file descriptor is
+/// passed as a consumed argument or returned as an owned value, and it never
+/// has the value `-1`.
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[unstable(feature = "io_safety", issue = "87074")]
+pub struct OwnedFd {
+    fd: RawFd,
+}
+
+impl BorrowedFd<'_> {
+    /// Return a `BorrowedFd` holding the given raw file descriptor.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `fd` must remain open for the duration of
+    /// the returned `BorrowedFd`, and it must not have the value `-1`.
+    #[inline]
+    #[unstable(feature = "io_safety", issue = "87074")]
+    pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self {
+        assert_ne!(fd, u32::MAX as RawFd);
+        // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+        unsafe { Self { fd, _phantom: PhantomData } }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsRawFd for BorrowedFd<'_> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsRawFd for OwnedFd {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl IntoRawFd for OwnedFd {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        let fd = self.fd;
+        forget(self);
+        fd
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl FromRawFd for OwnedFd {
+    /// Constructs a new instance of `Self` from the given raw file descriptor.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `fd` must be open and suitable for assuming
+    /// ownership. The resource must not require any cleanup other than `close`.
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        assert_ne!(fd, u32::MAX as RawFd);
+        // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+        unsafe { Self { fd } }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl Drop for OwnedFd {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            // Note that errors are ignored when closing a file descriptor. The
+            // reason for this is that if an error occurs we don't actually know if
+            // the file descriptor was closed or not, and if we retried (for
+            // something like EINTR), we might close another valid file descriptor
+            // opened after we closed ours.
+            let _ = libc::close(self.fd);
+        }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl fmt::Debug for BorrowedFd<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl fmt::Debug for OwnedFd {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
+    }
+}
+
+/// A trait to borrow the file descriptor from an underlying object.
+///
+/// This is only available on unix platforms and must be imported in order to
+/// call the method. Windows platforms have a corresponding `AsHandle` and
+/// `AsSocket` set of traits.
+#[unstable(feature = "io_safety", issue = "87074")]
+pub trait AsFd {
+    /// Borrows the file descriptor.
+    ///
+    /// # Example
+    ///
+    /// ```rust,no_run
+    /// # #![feature(io_safety)]
+    /// use std::fs::File;
+    /// # use std::io;
+    /// # #[cfg(target_os = "wasi")]
+    /// # use std::os::wasi::io::{AsFd, BorrowedFd};
+    /// # #[cfg(unix)]
+    /// # use std::os::unix::io::{AsFd, BorrowedFd};
+    ///
+    /// let mut f = File::open("foo.txt")?;
+    /// # #[cfg(any(unix, target_os = "wasi"))]
+    /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
+    /// # Ok::<(), io::Error>(())
+    /// ```
+    #[unstable(feature = "io_safety", issue = "87074")]
+    fn as_fd(&self) -> BorrowedFd<'_>;
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for BorrowedFd<'_> {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        *self
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for OwnedFd {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        // Safety: `OwnedFd` and `BorrowedFd` have the same validity
+        // invariants, and the `BorrowdFd` is bounded by the lifetime
+        // of `&self`.
+        unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for fs::File {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<fs::File> for OwnedFd {
+    #[inline]
+    fn from(file: fs::File) -> OwnedFd {
+        file.into_inner().into_inner().into_inner()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedFd> for fs::File {
+    #[inline]
+    fn from(owned_fd: OwnedFd) -> Self {
+        Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for crate::net::TcpStream {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().socket().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<crate::net::TcpStream> for OwnedFd {
+    #[inline]
+    fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
+        tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedFd> for crate::net::TcpStream {
+    #[inline]
+    fn from(owned_fd: OwnedFd) -> Self {
+        Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
+            owned_fd,
+        ))))
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for crate::net::TcpListener {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().socket().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<crate::net::TcpListener> for OwnedFd {
+    #[inline]
+    fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
+        tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedFd> for crate::net::TcpListener {
+    #[inline]
+    fn from(owned_fd: OwnedFd) -> Self {
+        Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
+            owned_fd,
+        ))))
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for crate::net::UdpSocket {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().socket().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<crate::net::UdpSocket> for OwnedFd {
+    #[inline]
+    fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
+        udp_socket.into_inner().into_socket().into_inner().into_inner().into()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedFd> for crate::net::UdpSocket {
+    #[inline]
+    fn from(owned_fd: OwnedFd) -> Self {
+        Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
+            owned_fd,
+        ))))
+    }
+}
diff --git a/library/std/src/os/unix/io.rs b/library/std/src/os/fd/raw.rs
index 07c30bfa9ed..f874cf0b42d 100644
--- a/library/std/src/os/unix/io.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -1,23 +1,25 @@
-//! Unix-specific extensions to general I/O primitives.
+//! Raw Unix-like file descriptors.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::fs;
 use crate::io;
 use crate::os::raw;
-use crate::sys;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+#[cfg(unix)]
+use crate::os::unix::io::OwnedFd;
+#[cfg(target_os = "wasi")]
+use crate::os::wasi::io::OwnedFd;
+use crate::sys_common::{AsInner, IntoInner};
 
 /// Raw file descriptors.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type RawFd = raw::c_int;
 
-/// A trait to extract the raw unix file descriptor from an underlying
-/// object.
+/// A trait to extract the raw file descriptor from an underlying object.
 ///
-/// This is only available on unix platforms and must be imported in order
-/// to call the method. Windows platforms have a corresponding `AsRawHandle`
-/// and `AsRawSocket` set of traits.
+/// This is only available on unix and WASI platforms and must be imported in
+/// order to call the method. Windows platforms have a corresponding
+/// `AsRawHandle` and `AsRawSocket` set of traits.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait AsRawFd {
     /// Extracts the raw file descriptor.
@@ -31,10 +33,14 @@ pub trait AsRawFd {
     /// ```no_run
     /// use std::fs::File;
     /// # use std::io;
+    /// #[cfg(unix)]
     /// use std::os::unix::io::{AsRawFd, RawFd};
+    /// #[cfg(target_os = "wasi")]
+    /// use std::os::wasi::io::{AsRawFd, RawFd};
     ///
     /// let mut f = File::open("foo.txt")?;
     /// // Note that `raw_fd` is only valid as long as `f` exists.
+    /// #[cfg(any(unix, target_os = "wasi"))]
     /// let raw_fd: RawFd = f.as_raw_fd();
     /// # Ok::<(), io::Error>(())
     /// ```
@@ -64,12 +70,17 @@ pub trait FromRawFd {
     /// ```no_run
     /// use std::fs::File;
     /// # use std::io;
+    /// #[cfg(unix)]
     /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
+    /// #[cfg(target_os = "wasi")]
+    /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd};
     ///
     /// let f = File::open("foo.txt")?;
+    /// # #[cfg(any(unix, target_os = "wasi"))]
     /// let raw_fd: RawFd = f.into_raw_fd();
     /// // SAFETY: no other functions should call `from_raw_fd`, so there
     /// // is only one owner for the file descriptor.
+    /// # #[cfg(any(unix, target_os = "wasi"))]
     /// let f = unsafe { File::from_raw_fd(raw_fd) };
     /// # Ok::<(), io::Error>(())
     /// ```
@@ -92,9 +103,13 @@ pub trait IntoRawFd {
     /// ```no_run
     /// use std::fs::File;
     /// # use std::io;
+    /// #[cfg(unix)]
     /// use std::os::unix::io::{IntoRawFd, RawFd};
+    /// #[cfg(target_os = "wasi")]
+    /// use std::os::wasi::io::{IntoRawFd, RawFd};
     ///
     /// let f = File::open("foo.txt")?;
+    /// #[cfg(any(unix, target_os = "wasi"))]
     /// let raw_fd: RawFd = f.into_raw_fd();
     /// # Ok::<(), io::Error>(())
     /// ```
@@ -128,21 +143,21 @@ impl FromRawFd for RawFd {
 impl AsRawFd for fs::File {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
+        self.as_inner().as_raw_fd()
     }
 }
 #[stable(feature = "from_raw_os", since = "1.1.0")]
 impl FromRawFd for fs::File {
     #[inline]
     unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
-        fs::File::from_inner(sys::fs::File::from_inner(fd))
+        unsafe { fs::File::from(OwnedFd::from_raw_fd(fd)) }
     }
 }
 #[stable(feature = "into_raw_os", since = "1.4.0")]
 impl IntoRawFd for fs::File {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
+        self.into_inner().into_inner().into_raw_fd()
     }
 }
 
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
index 6daff0f003c..e3e7143c851 100644
--- a/library/std/src/os/linux/process.rs
+++ b/library/std/src/os/linux/process.rs
@@ -3,7 +3,7 @@
 #![unstable(feature = "linux_pidfd", issue = "82971")]
 
 use crate::io::Result;
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::process;
 use crate::sealed::Sealed;
 #[cfg(not(doc))]
@@ -69,19 +69,37 @@ impl IntoInner<FileDesc> for PidFd {
 
 impl AsRawFd for PidFd {
     fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().raw()
+        self.as_inner().as_raw_fd()
     }
 }
 
 impl FromRawFd for PidFd {
     unsafe fn from_raw_fd(fd: RawFd) -> Self {
-        Self::from_inner(FileDesc::new(fd))
+        Self::from_inner(FileDesc::from_raw_fd(fd))
     }
 }
 
 impl IntoRawFd for PidFd {
     fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_raw()
+        self.into_inner().into_raw_fd()
+    }
+}
+
+impl AsFd for PidFd {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+impl From<OwnedFd> for PidFd {
+    fn from(fd: OwnedFd) -> Self {
+        Self::from_inner(FileDesc::from_inner(fd))
+    }
+}
+
+impl From<PidFd> for OwnedFd {
+    fn from(pid_fd: PidFd) -> Self {
+        pid_fd.into_inner().into_inner()
     }
 }
 
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 4c9814919cd..79e69673007 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -121,3 +121,6 @@ mod imp {
 #[cfg(not(doc))]
 #[stable(feature = "os", since = "1.0.0")]
 pub use imp::*;
+
+#[cfg(any(unix, target_os = "wasi", doc))]
+mod fd;
diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs
new file mode 100644
index 00000000000..7795db7abc0
--- /dev/null
+++ b/library/std/src/os/unix/io/fd.rs
@@ -0,0 +1,9 @@
+//! Owned and borrowed file descriptors.
+
+#![unstable(feature = "io_safety", issue = "87074")]
+
+// Tests for this module
+#[cfg(test)]
+mod tests;
+
+pub use crate::os::fd::owned::*;
diff --git a/library/std/src/os/unix/io/fd/tests.rs b/library/std/src/os/unix/io/fd/tests.rs
new file mode 100644
index 00000000000..84d2a7a1a91
--- /dev/null
+++ b/library/std/src/os/unix/io/fd/tests.rs
@@ -0,0 +1,11 @@
+use crate::mem::size_of;
+use crate::os::unix::io::RawFd;
+
+#[test]
+fn test_raw_fd_layout() {
+    // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
+    // and `rustc_layout_scalar_valid_range_end`, with values that depend on
+    // the bit width of `RawFd`. If this ever changes, those values will need
+    // to be updated.
+    assert_eq!(size_of::<RawFd>(), 4);
+}
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
new file mode 100644
index 00000000000..0fd9591b016
--- /dev/null
+++ b/library/std/src/os/unix/io/mod.rs
@@ -0,0 +1,57 @@
+//! Unix-specific extensions to general I/O primitives.
+//!
+//! Just like raw pointers, raw file descriptors point to resources with
+//! dynamic lifetimes, and they can dangle if they outlive their resources
+//! or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing file descriptors,
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type               | Analogous to |
+//! | ------------------ | ------------ |
+//! | [`RawFd`]          | `*const _`   |
+//! | [`BorrowedFd<'a>`] | `&'a _`      |
+//! | [`OwnedFd`]        | `Box<_>`     |
+//!
+//! Like raw pointers, `RawFd` values are primitive values. And in new code,
+//! they should be considered unsafe to do I/O on (analogous to dereferencing
+//! them). Rust did not always provide this guidance, so existing code in the
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
+//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
+//! using to `BorrowedFd` or `OwnedFd` instead.
+//!
+//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
+//! that they don't outlive the resource they point to. These are safe to
+//! use. `BorrowedFd` values may be used in APIs which provide safe access to
+//! any system call except for:
+//!  - `close`, because that would end the dynamic lifetime of the resource
+//!    without ending the lifetime of the file descriptor.
+//!  - `dup2`/`dup3`, in the second argument, because this argument is
+//!    closed and assigned a new resource, which may break the assumptions
+//!    other code using that file descriptor.
+//! This list doesn't include `mmap`, since `mmap` does do a proper borrow of
+//! its file descriptor argument. That said, `mmap` is unsafe for other
+//! reasons: it operates on raw pointers, and it can have undefined behavior if
+//! the underlying storage is mutated. Mutations may come from other processes,
+//! or from the same process if the API provides `BorrowedFd` access, since as
+//! mentioned earlier, `BorrowedFd` values may be used in APIs which provide
+//! safe access to any system call. Consequently, code using `mmap` and
+//! presenting a safe API must take full responsibility for ensuring that safe
+//! Rust code cannot evoke undefined behavior through it.
+//!
+//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
+//! and free (close) it when they are dropped.
+//!
+//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod fd;
+mod raw;
+
+#[unstable(feature = "io_safety", issue = "87074")]
+pub use fd::*;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::*;
diff --git a/library/std/src/os/unix/io/raw.rs b/library/std/src/os/unix/io/raw.rs
new file mode 100644
index 00000000000..6317e317471
--- /dev/null
+++ b/library/std/src/os/unix/io/raw.rs
@@ -0,0 +1,5 @@
+//! Unix-specific extensions to general I/O primitives.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 6c73d4b21dd..17a02595724 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -108,7 +108,7 @@ pub mod prelude {
     pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt};
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+    pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::process::{CommandExt, ExitStatusExt};
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index 9e39f70f68e..f11eec18cc5 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -21,7 +21,7 @@ use super::{sockaddr_un, SocketAddr};
 ))]
 use crate::io::{IoSlice, IoSliceMut};
 use crate::net::Shutdown;
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::path::Path;
 use crate::sys::cvt;
 use crate::sys::net::Socket;
@@ -106,7 +106,7 @@ impl UnixDatagram {
             let socket = UnixDatagram::unbound()?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
+            cvt(libc::bind(socket.as_raw_fd(), &addr as *const _ as *const _, len as _))?;
 
             Ok(socket)
         }
@@ -187,7 +187,7 @@ impl UnixDatagram {
         unsafe {
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?;
+            cvt(libc::connect(self.as_raw_fd(), &addr as *const _ as *const _, len))?;
         }
         Ok(())
     }
@@ -229,7 +229,7 @@ impl UnixDatagram {
     /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn local_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
     }
 
     /// Returns the address of this socket's peer.
@@ -253,7 +253,7 @@ impl UnixDatagram {
     /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+        SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) })
     }
 
     fn recv_from_flags(
@@ -264,7 +264,7 @@ impl UnixDatagram {
         let mut count = 0;
         let addr = SocketAddr::new(|addr, len| unsafe {
             count = libc::recvfrom(
-                *self.0.as_inner(),
+                self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut _,
                 buf.len(),
                 flags,
@@ -462,7 +462,7 @@ impl UnixDatagram {
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
             let count = cvt(libc::sendto(
-                *self.0.as_inner(),
+                self.as_raw_fd(),
                 buf.as_ptr() as *const _,
                 buf.len(),
                 MSG_NOSIGNAL,
@@ -881,7 +881,7 @@ impl UnixDatagram {
 impl AsRawFd for UnixDatagram {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        *self.0.as_inner()
+        self.0.as_inner().as_raw_fd()
     }
 }
 
@@ -889,7 +889,7 @@ impl AsRawFd for UnixDatagram {
 impl FromRawFd for UnixDatagram {
     #[inline]
     unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
-        UnixDatagram(Socket::from_inner(fd))
+        UnixDatagram(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
     }
 }
 
@@ -897,6 +897,30 @@ impl FromRawFd for UnixDatagram {
 impl IntoRawFd for UnixDatagram {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        self.0.into_inner()
+        self.0.into_inner().into_inner().into_raw_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for UnixDatagram {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_inner().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<UnixDatagram> for OwnedFd {
+    #[inline]
+    fn from(unix_datagram: UnixDatagram) -> OwnedFd {
+        unsafe { OwnedFd::from_raw_fd(unix_datagram.into_raw_fd()) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedFd> for UnixDatagram {
+    #[inline]
+    fn from(owned: OwnedFd) -> Self {
+        unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
     }
 }
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index bdd08fe8380..9066c71794f 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -1,5 +1,5 @@
 use super::{sockaddr_un, SocketAddr, UnixStream};
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::path::Path;
 use crate::sys::cvt;
 use crate::sys::net::Socket;
@@ -74,8 +74,8 @@ impl UnixListener {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
-            cvt(libc::listen(*inner.as_inner(), 128))?;
+            cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
+            cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?;
 
             Ok(UnixListener(inner))
         }
@@ -150,7 +150,7 @@ impl UnixListener {
     /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn local_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
     }
 
     /// Moves the socket into or out of nonblocking mode.
@@ -242,7 +242,7 @@ impl UnixListener {
 impl AsRawFd for UnixListener {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        *self.0.as_inner()
+        self.0.as_inner().as_raw_fd()
     }
 }
 
@@ -250,7 +250,7 @@ impl AsRawFd for UnixListener {
 impl FromRawFd for UnixListener {
     #[inline]
     unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
-        UnixListener(Socket::from_inner(fd))
+        UnixListener(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
     }
 }
 
@@ -258,7 +258,7 @@ impl FromRawFd for UnixListener {
 impl IntoRawFd for UnixListener {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        self.0.into_inner()
+        self.0.into_inner().into_inner().into_raw_fd()
     }
 }
 
diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs
index 3088ffb5e5c..d462bd4b5f7 100644
--- a/library/std/src/os/unix/net/mod.rs
+++ b/library/std/src/os/unix/net/mod.rs
@@ -25,7 +25,6 @@ mod addr;
 mod ancillary;
 mod datagram;
 mod listener;
-mod raw_fd;
 mod stream;
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
@@ -48,7 +47,5 @@ pub use self::ancillary::*;
 pub use self::datagram::*;
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub use self::listener::*;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::raw_fd::*;
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub use self::stream::*;
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index fba084375e5..4119de3c03c 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -13,7 +13,7 @@ use super::{sockaddr_un, SocketAddr};
 use crate::fmt;
 use crate::io::{self, Initializer, IoSlice, IoSliceMut};
 use crate::net::Shutdown;
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 #[cfg(any(
     target_os = "android",
     target_os = "linux",
@@ -28,7 +28,7 @@ use crate::os::unix::ucred;
 use crate::path::Path;
 use crate::sys::cvt;
 use crate::sys::net::Socket;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys_common::{AsInner, FromInner};
 use crate::time::Duration;
 
 #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
@@ -101,7 +101,7 @@ impl UnixStream {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
+            cvt(libc::connect(inner.as_raw_fd(), &addr as *const _ as *const _, len))?;
             Ok(UnixStream(inner))
         }
     }
@@ -167,7 +167,7 @@ impl UnixStream {
     /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn local_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
     }
 
     /// Returns the socket address of the remote half of this connection.
@@ -185,7 +185,7 @@ impl UnixStream {
     /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+        SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) })
     }
 
     /// Gets the peer credentials for this Unix domain socket.
@@ -659,7 +659,7 @@ impl<'a> io::Write for &'a UnixStream {
 impl AsRawFd for UnixStream {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        *self.0.as_inner()
+        self.0.as_raw_fd()
     }
 }
 
@@ -667,7 +667,7 @@ impl AsRawFd for UnixStream {
 impl FromRawFd for UnixStream {
     #[inline]
     unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
-        UnixStream(Socket::from_inner(fd))
+        UnixStream(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
     }
 }
 
@@ -675,6 +675,30 @@ impl FromRawFd for UnixStream {
 impl IntoRawFd for UnixStream {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        self.0.into_inner()
+        self.0.into_raw_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for UnixStream {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<UnixStream> for OwnedFd {
+    #[inline]
+    fn from(unix_stream: UnixStream) -> OwnedFd {
+        unsafe { OwnedFd::from_raw_fd(unix_stream.into_raw_fd()) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedFd> for UnixStream {
+    #[inline]
+    fn from(owned: OwnedFd) -> Self {
+        unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
     }
 }
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 615290d2703..650dcbabbae 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -4,7 +4,7 @@
 
 use crate::ffi::OsStr;
 use crate::io;
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::process;
 use crate::sealed::Sealed;
 use crate::sys;
@@ -321,7 +321,17 @@ impl ExitStatusExt for process::ExitStatusError {
 impl FromRawFd for process::Stdio {
     #[inline]
     unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
-        let fd = sys::fd::FileDesc::new(fd);
+        let fd = sys::fd::FileDesc::from_raw_fd(fd);
+        let io = sys::process::Stdio::Fd(fd);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedFd> for process::Stdio {
+    #[inline]
+    fn from(fd: OwnedFd) -> process::Stdio {
+        let fd = sys::fd::FileDesc::from_inner(fd);
         let io = sys::process::Stdio::Fd(fd);
         process::Stdio::from_inner(io)
     }
@@ -331,7 +341,7 @@ impl FromRawFd for process::Stdio {
 impl AsRawFd for process::ChildStdin {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
+        self.as_inner().as_raw_fd()
     }
 }
 
@@ -339,7 +349,7 @@ impl AsRawFd for process::ChildStdin {
 impl AsRawFd for process::ChildStdout {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
+        self.as_inner().as_raw_fd()
     }
 }
 
@@ -347,7 +357,7 @@ impl AsRawFd for process::ChildStdout {
 impl AsRawFd for process::ChildStderr {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
+        self.as_inner().as_raw_fd()
     }
 }
 
@@ -355,7 +365,7 @@ impl AsRawFd for process::ChildStderr {
 impl IntoRawFd for process::ChildStdin {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
+        self.into_inner().into_inner().into_raw_fd()
     }
 }
 
@@ -363,7 +373,7 @@ impl IntoRawFd for process::ChildStdin {
 impl IntoRawFd for process::ChildStdout {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
+        self.into_inner().into_inner().into_raw_fd()
     }
 }
 
@@ -371,7 +381,55 @@ impl IntoRawFd for process::ChildStdout {
 impl IntoRawFd for process::ChildStderr {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
+        self.into_inner().into_inner().into_raw_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for crate::process::ChildStdin {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<crate::process::ChildStdin> for OwnedFd {
+    #[inline]
+    fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
+        child_stdin.into_inner().into_inner().into_inner()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for crate::process::ChildStdout {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<crate::process::ChildStdout> for OwnedFd {
+    #[inline]
+    fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
+        child_stdout.into_inner().into_inner().into_inner()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for crate::process::ChildStderr {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<crate::process::ChildStderr> for OwnedFd {
+    #[inline]
+    fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
+        child_stderr.into_inner().into_inner().into_inner()
     }
 }
 
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index bd30d6ae3f3..3df27563e21 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -228,35 +228,35 @@ pub trait FileExt {
 
 impl FileExt for fs::File {
     fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
-        self.as_inner().fd().pread(bufs, offset)
+        self.as_inner().as_inner().pread(bufs, offset)
     }
 
     fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
-        self.as_inner().fd().pwrite(bufs, offset)
+        self.as_inner().as_inner().pwrite(bufs, offset)
     }
 
     fn tell(&self) -> io::Result<u64> {
-        self.as_inner().fd().tell()
+        self.as_inner().as_inner().tell()
     }
 
     fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
-        self.as_inner().fd().set_flags(flags)
+        self.as_inner().as_inner().set_flags(flags)
     }
 
     fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> {
-        self.as_inner().fd().set_rights(rights, inheriting)
+        self.as_inner().as_inner().set_rights(rights, inheriting)
     }
 
     fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
-        self.as_inner().fd().advise(offset, len, advice)
+        self.as_inner().as_inner().advise(offset, len, advice)
     }
 
     fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
-        self.as_inner().fd().allocate(offset, len)
+        self.as_inner().as_inner().allocate(offset, len)
     }
 
     fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> {
-        self.as_inner().fd().create_directory(osstr2str(dir.as_ref().as_ref())?)
+        self.as_inner().as_inner().create_directory(osstr2str(dir.as_ref().as_ref())?)
     }
 
     fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
@@ -269,11 +269,11 @@ impl FileExt for fs::File {
     }
 
     fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
-        self.as_inner().fd().unlink_file(osstr2str(path.as_ref().as_ref())?)
+        self.as_inner().as_inner().unlink_file(osstr2str(path.as_ref().as_ref())?)
     }
 
     fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
-        self.as_inner().fd().remove_directory(osstr2str(path.as_ref().as_ref())?)
+        self.as_inner().as_inner().remove_directory(osstr2str(path.as_ref().as_ref())?)
     }
 }
 
@@ -486,10 +486,10 @@ pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
     new_fd: &File,
     new_path: U,
 ) -> io::Result<()> {
-    old_fd.as_inner().fd().link(
+    old_fd.as_inner().as_inner().link(
         old_flags,
         osstr2str(old_path.as_ref().as_ref())?,
-        new_fd.as_inner().fd(),
+        new_fd.as_inner().as_inner(),
         osstr2str(new_path.as_ref().as_ref())?,
     )
 }
@@ -503,9 +503,9 @@ pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
     new_fd: &File,
     new_path: U,
 ) -> io::Result<()> {
-    old_fd.as_inner().fd().rename(
+    old_fd.as_inner().as_inner().rename(
         osstr2str(old_path.as_ref().as_ref())?,
-        new_fd.as_inner().fd(),
+        new_fd.as_inner().as_inner(),
         osstr2str(new_path.as_ref().as_ref())?,
     )
 }
@@ -519,7 +519,7 @@ pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
     new_path: U,
 ) -> io::Result<()> {
     fd.as_inner()
-        .fd()
+        .as_inner()
         .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?)
 }
 
diff --git a/library/std/src/os/wasi/io.rs b/library/std/src/os/wasi/io.rs
deleted file mode 100644
index b6bc74da8e7..00000000000
--- a/library/std/src/os/wasi/io.rs
+++ /dev/null
@@ -1,208 +0,0 @@
-//! WASI-specific extensions to general I/O primitives
-
-#![deny(unsafe_op_in_unsafe_fn)]
-#![unstable(feature = "wasi_ext", issue = "71213")]
-
-use crate::fs;
-use crate::io;
-use crate::net;
-use crate::os::raw;
-use crate::sys;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-
-/// Raw file descriptors.
-///
-/// This has type `c_int` to ease compatibility with code that also compiles on
-/// Unix configurations, however unlike Unix and POSIX, in WASI negative file
-/// descriptors are valid. Only `-1` is reserved for indicating errors. Code
-/// intending to be portable across Unix platforms and WASI should avoid
-/// assuming that negative file descriptors are invalid.
-pub type RawFd = raw::c_int;
-
-/// A trait to extract the raw WASI file descriptor from an underlying
-/// object.
-pub trait AsRawFd {
-    /// Extracts the raw file descriptor.
-    ///
-    /// This method does **not** pass ownership of the raw file descriptor
-    /// to the caller. The descriptor is only guaranteed to be valid while
-    /// the original object has not yet been destroyed.
-    fn as_raw_fd(&self) -> RawFd;
-}
-
-/// A trait to express the ability to construct an object from a raw file
-/// descriptor.
-pub trait FromRawFd {
-    /// Constructs a new instance of `Self` from the given raw file
-    /// descriptor.
-    ///
-    /// This function **consumes ownership** of the specified file
-    /// descriptor. The returned object will take responsibility for closing
-    /// it when the object goes out of scope.
-    ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
-    unsafe fn from_raw_fd(fd: RawFd) -> Self;
-}
-
-/// A trait to express the ability to consume an object and acquire ownership of
-/// its raw file descriptor.
-pub trait IntoRawFd {
-    /// Consumes this object, returning the raw underlying file descriptor.
-    ///
-    /// This function **transfers ownership** of the underlying file descriptor
-    /// to the caller. Callers are then the unique owners of the file descriptor
-    /// and must close the descriptor once it's no longer needed.
-    fn into_raw_fd(self) -> RawFd;
-}
-
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl AsRawFd for RawFd {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self
-    }
-}
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl IntoRawFd for RawFd {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self
-    }
-}
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl FromRawFd for RawFd {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
-        fd
-    }
-}
-
-impl AsRawFd for net::TcpStream {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for net::TcpStream {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
-        net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for net::TcpStream {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for net::TcpListener {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for net::TcpListener {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
-        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for net::TcpListener {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for net::UdpSocket {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for net::UdpSocket {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
-        net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for net::UdpSocket {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for fs::File {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for fs::File {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
-        fs::File::from_inner(sys::fs::File::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for fs::File {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for io::Stdin {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO
-    }
-}
-
-impl AsRawFd for io::Stdout {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO
-    }
-}
-
-impl AsRawFd for io::Stderr {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO
-    }
-}
-
-impl<'a> AsRawFd for io::StdinLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO
-    }
-}
-
-impl<'a> AsRawFd for io::StdoutLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO
-    }
-}
-
-impl<'a> AsRawFd for io::StderrLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO
-    }
-}
diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs
new file mode 100644
index 00000000000..930aca887e3
--- /dev/null
+++ b/library/std/src/os/wasi/io/fd.rs
@@ -0,0 +1,9 @@
+//! Owned and borrowed file descriptors.
+
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+// Tests for this module
+#[cfg(test)]
+mod tests;
+
+pub use crate::os::fd::owned::*;
diff --git a/library/std/src/os/wasi/io/fd/tests.rs b/library/std/src/os/wasi/io/fd/tests.rs
new file mode 100644
index 00000000000..418274752b0
--- /dev/null
+++ b/library/std/src/os/wasi/io/fd/tests.rs
@@ -0,0 +1,11 @@
+use crate::mem::size_of;
+use crate::os::wasi::io::RawFd;
+
+#[test]
+fn test_raw_fd_layout() {
+    // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
+    // and `rustc_layout_scalar_valid_range_end`, with values that depend on
+    // the bit width of `RawFd`. If this ever changes, those values will need
+    // to be updated.
+    assert_eq!(size_of::<RawFd>(), 4);
+}
diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs
new file mode 100644
index 00000000000..6c884e2eaf4
--- /dev/null
+++ b/library/std/src/os/wasi/io/mod.rs
@@ -0,0 +1,12 @@
+//! WASI-specific extensions to general I/O primitives.
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+mod fd;
+mod raw;
+
+#[unstable(feature = "wasi_ext", issue = "71213")]
+pub use fd::*;
+#[unstable(feature = "wasi_ext", issue = "71213")]
+pub use raw::*;
diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs
new file mode 100644
index 00000000000..0e0c5824e34
--- /dev/null
+++ b/library/std/src/os/wasi/io/raw.rs
@@ -0,0 +1,5 @@
+//! WASI-specific extensions to general I/O primitives.
+
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs
index 44b7c32e956..d767c149dc5 100644
--- a/library/std/src/os/wasi/mod.rs
+++ b/library/std/src/os/wasi/mod.rs
@@ -32,6 +32,7 @@
 pub mod ffi;
 pub mod fs;
 pub mod io;
+pub mod net;
 
 /// A prelude for conveniently writing platform-specific code.
 ///
@@ -49,5 +50,5 @@ pub mod prelude {
     pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+    pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 }
diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs
new file mode 100644
index 00000000000..e6bcf87887f
--- /dev/null
+++ b/library/std/src/os/wasi/net/mod.rs
@@ -0,0 +1,3 @@
+//! WASI-specific networking functionality
+
+#![unstable(feature = "wasi_ext", issue = "71213")]
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
new file mode 100644
index 00000000000..72a17adb3b4
--- /dev/null
+++ b/library/std/src/os/windows/io/handle.rs
@@ -0,0 +1,386 @@
+//! Owned and borrowed OS handles.
+
+#![unstable(feature = "io_safety", issue = "87074")]
+
+use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
+use crate::convert::TryFrom;
+use crate::ffi::c_void;
+use crate::fmt;
+use crate::fs;
+use crate::marker::PhantomData;
+use crate::mem::forget;
+use crate::ptr::NonNull;
+use crate::sys::c;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// A borrowed handle.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the handle.
+///
+/// This uses `repr(transparent)` and has the representation of a host handle,
+/// so it can be used in FFI in places where a handle is passed as an argument,
+/// it is not captured or consumed, and it is never null.
+///
+/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
+/// sometimes a valid handle value. See [here] for the full story.
+///
+/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[unstable(feature = "io_safety", issue = "87074")]
+pub struct BorrowedHandle<'handle> {
+    handle: NonNull<c_void>,
+    _phantom: PhantomData<&'handle OwnedHandle>,
+}
+
+/// An owned handle.
+///
+/// This closes the handle on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host handle,
+/// so it can be used in FFI in places where a handle is passed as a consumed
+/// argument or returned as an owned value, and is never null.
+///
+/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
+/// sometimes a valid handle value. See [here] for the full story. For APIs
+/// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead
+/// of null, use [`HandleOrInvalid`] instead of `Option<OwnedHandle>`.
+///
+/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
+/// it must not be used with handles to open registry keys which need to be
+/// closed with [`RegCloseKey`] instead.
+///
+/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
+/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
+///
+/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+#[repr(transparent)]
+#[unstable(feature = "io_safety", issue = "87074")]
+pub struct OwnedHandle {
+    handle: NonNull<c_void>,
+}
+
+/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
+/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
+/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
+/// FFI declarations.
+///
+/// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an
+/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
+/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
+/// checking for `INVALID_HANDLE_VALUE` first.
+///
+/// If this holds a valid handle, it will close the handle on drop.
+#[repr(transparent)]
+#[unstable(feature = "io_safety", issue = "87074")]
+#[derive(Debug)]
+pub struct HandleOrInvalid(Option<OwnedHandle>);
+
+// The Windows [`HANDLE`] type may be transferred across and shared between
+// thread boundaries (despite containing a `*mut void`, which in general isn't
+// `Send` or `Sync`).
+//
+// [`HANDLE`]: std::os::windows::raw::HANDLE
+unsafe impl Send for OwnedHandle {}
+unsafe impl Send for HandleOrInvalid {}
+unsafe impl Send for BorrowedHandle<'_> {}
+unsafe impl Sync for OwnedHandle {}
+unsafe impl Sync for HandleOrInvalid {}
+unsafe impl Sync for BorrowedHandle<'_> {}
+
+impl BorrowedHandle<'_> {
+    /// Return a `BorrowedHandle` holding the given raw handle.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `handle` must be a valid open handle, it
+    /// must remain open for the duration of the returned `BorrowedHandle`, and
+    /// it must not be null.
+    ///
+    /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
+    /// sometimes a valid handle value. See [here] for the full story.
+    ///
+    /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+    #[inline]
+    #[unstable(feature = "io_safety", issue = "87074")]
+    pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self {
+        assert!(!handle.is_null());
+        Self { handle: NonNull::new_unchecked(handle), _phantom: PhantomData }
+    }
+}
+
+impl TryFrom<HandleOrInvalid> for OwnedHandle {
+    type Error = ();
+
+    #[inline]
+    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
+        // In theory, we ought to be able to assume that the pointer here is
+        // never null, use `OwnedHandle` rather than `Option<OwnedHandle>`, and
+        // obviate the the panic path here.  Unfortunately, Win32 documentation
+        // doesn't explicitly guarantee this anywhere.
+        //
+        // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a
+        // null handle indicates an absent value, which wouldn't work if null
+        // were a valid handle value, so it seems very unlikely that it could
+        // ever return null. But who knows?
+        //
+        // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
+        let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!");
+        if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE {
+            Err(())
+        } else {
+            Ok(owned_handle)
+        }
+    }
+}
+
+impl AsRawHandle for BorrowedHandle<'_> {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.handle.as_ptr()
+    }
+}
+
+impl AsRawHandle for OwnedHandle {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.handle.as_ptr()
+    }
+}
+
+impl IntoRawHandle for OwnedHandle {
+    #[inline]
+    fn into_raw_handle(self) -> RawHandle {
+        let handle = self.handle.as_ptr();
+        forget(self);
+        handle
+    }
+}
+
+impl FromRawHandle for OwnedHandle {
+    /// Constructs a new instance of `Self` from the given raw handle.
+    ///
+    /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
+    /// use `INVALID_HANDLE_VALUE` to indicate failure.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `handle` must be open and suitable for
+    /// assuming ownership. The resource must not require any cleanup other
+    /// than `CloseHandle`.
+    ///
+    /// In particular, it must not be used with handles to open registry
+    /// keys which need to be closed with [`RegCloseKey`] instead.
+    ///
+    /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
+    /// sometimes a valid handle value. See [here] for the full story.
+    ///
+    /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
+    /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+    #[inline]
+    unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+        assert!(!handle.is_null());
+        Self { handle: NonNull::new_unchecked(handle) }
+    }
+}
+
+impl FromRawHandle for HandleOrInvalid {
+    /// Constructs a new instance of `Self` from the given `RawHandle` returned
+    /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
+    /// failure, such as `CreateFileW`.
+    ///
+    /// Use `Option<OwnedHandle>` instead of `HandleOrInvalid` for APIs that
+    /// use null to indicate failure.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `handle` must be either open and otherwise
+    /// unowned, or equal to `INVALID_HANDLE_VALUE` (-1). It must not be null.
+    /// Note that not all Windows APIs use `INVALID_HANDLE_VALUE` for errors;
+    /// see [here] for the full story.
+    ///
+    /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+    #[inline]
+    unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+        // We require non-null here to catch errors earlier.
+        Self(Some(OwnedHandle::from_raw_handle(handle)))
+    }
+}
+
+impl Drop for OwnedHandle {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            let _ = c::CloseHandle(self.handle.as_ptr());
+        }
+    }
+}
+
+impl fmt::Debug for BorrowedHandle<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish()
+    }
+}
+
+impl fmt::Debug for OwnedHandle {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OwnedHandle").field("handle", &self.handle).finish()
+    }
+}
+
+/// A trait to borrow the handle from an underlying object.
+#[unstable(feature = "io_safety", issue = "87074")]
+pub trait AsHandle {
+    /// Borrows the handle.
+    ///
+    /// # Example
+    ///
+    /// ```rust,no_run
+    /// # #![feature(io_safety)]
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::windows::io::{AsHandle, BorrowedHandle};
+    ///
+    /// let mut f = File::open("foo.txt")?;
+    /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle();
+    /// # Ok::<(), io::Error>(())
+    /// ```
+    fn as_handle(&self) -> BorrowedHandle<'_>;
+}
+
+impl AsHandle for BorrowedHandle<'_> {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        *self
+    }
+}
+
+impl AsHandle for OwnedHandle {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity
+        // invariants, and the `BorrowdHandle` is bounded by the lifetime
+        // of `&self`.
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandle for fs::File {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        self.as_inner().as_handle()
+    }
+}
+
+impl From<fs::File> for OwnedHandle {
+    #[inline]
+    fn from(file: fs::File) -> OwnedHandle {
+        file.into_inner().into_inner().into_inner().into()
+    }
+}
+
+impl From<OwnedHandle> for fs::File {
+    #[inline]
+    fn from(owned: OwnedHandle) -> Self {
+        Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned)))
+    }
+}
+
+impl AsHandle for crate::io::Stdin {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl<'a> AsHandle for crate::io::StdinLock<'a> {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandle for crate::io::Stdout {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl<'a> AsHandle for crate::io::StdoutLock<'a> {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandle for crate::io::Stderr {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl<'a> AsHandle for crate::io::StderrLock<'a> {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandle for crate::process::ChildStdin {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl From<crate::process::ChildStdin> for OwnedHandle {
+    #[inline]
+    fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle {
+        unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) }
+    }
+}
+
+impl AsHandle for crate::process::ChildStdout {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl From<crate::process::ChildStdout> for OwnedHandle {
+    #[inline]
+    fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle {
+        unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) }
+    }
+}
+
+impl AsHandle for crate::process::ChildStderr {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl From<crate::process::ChildStderr> for OwnedHandle {
+    #[inline]
+    fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
+        unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) }
+    }
+}
+
+impl<T> AsHandle for crate::thread::JoinHandle<T> {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl<T> From<crate::thread::JoinHandle<T>> for OwnedHandle {
+    #[inline]
+    fn from(join_handle: crate::thread::JoinHandle<T>) -> OwnedHandle {
+        join_handle.into_inner().into_handle().into_inner()
+    }
+}
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
new file mode 100644
index 00000000000..2f6f0769548
--- /dev/null
+++ b/library/std/src/os/windows/io/mod.rs
@@ -0,0 +1,56 @@
+//! Windows-specific extensions to general I/O primitives.
+//!
+//! Just like raw pointers, raw Windows handles and sockets point to resources
+//! with dynamic lifetimes, and they can dangle if they outlive their resources
+//! or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing raw handles and sockets
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type                   | Analogous to |
+//! | ---------------------- | ------------ |
+//! | [`RawHandle`]          | `*const _`   |
+//! | [`RawSocket`]          | `*const _`   |
+//! |                        |              |
+//! | [`BorrowedHandle<'a>`] | `&'a _`      |
+//! | [`BorrowedSocket<'a>`] | `&'a _`      |
+//! |                        |              |
+//! | [`OwnedHandle`]        | `Box<_>`     |
+//! | [`OwnedSocket`]        | `Box<_>`     |
+//!
+//! Like raw pointers, `RawHandle` and `RawSocket` values are primitive values.
+//! And in new code, they should be considered unsafe to do I/O on (analogous
+//! to dereferencing them). Rust did not always provide this guidance, so
+//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and
+//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable,
+//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs
+//! that dereference `RawHandle` and `RawSocket` values, or by using to
+//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`.
+//!
+//! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a
+//! lifetime, to ensure that they don't outlive the resource they point to.
+//! These are safe to use. `BorrowedHandle` and `BorrowedSocket` values may be
+//! used in APIs which provide safe access to any system call except for
+//! `CloseHandle`, `closesocket`, or any other call that would end the
+//! dynamic lifetime of the resource without ending the lifetime of the
+//! handle or socket.
+//!
+//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
+//! resource they point to, and free (close) it when they are dropped.
+//!
+//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
+//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod handle;
+mod raw;
+mod socket;
+
+#[unstable(feature = "io_safety", issue = "87074")]
+pub use handle::*;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::*;
+#[unstable(feature = "io_safety", issue = "87074")]
+pub use socket::*;
diff --git a/library/std/src/os/windows/io.rs b/library/std/src/os/windows/io/raw.rs
index 31b5d015ed0..c7f122048a1 100644
--- a/library/std/src/os/windows/io.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -5,6 +5,7 @@
 use crate::fs;
 use crate::io;
 use crate::net;
+use crate::os::windows::io::{OwnedHandle, OwnedSocket};
 use crate::os::windows::raw;
 use crate::sys;
 use crate::sys::c;
@@ -61,7 +62,7 @@ pub trait IntoRawHandle {
 impl AsRawHandle for fs::File {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as RawHandle
+        self.as_inner().as_raw_handle() as RawHandle
     }
 }
 
@@ -112,7 +113,9 @@ impl FromRawHandle for fs::File {
     #[inline]
     unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
         let handle = handle as c::HANDLE;
-        fs::File::from_inner(sys::fs::File::from_inner(handle))
+        fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner(
+            OwnedHandle::from_raw_handle(handle),
+        )))
     }
 }
 
@@ -120,7 +123,7 @@ impl FromRawHandle for fs::File {
 impl IntoRawHandle for fs::File {
     #[inline]
     fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
+        self.into_inner().into_raw_handle() as *mut _
     }
 }
 
@@ -166,21 +169,21 @@ pub trait IntoRawSocket {
 impl AsRawSocket for net::TcpStream {
     #[inline]
     fn as_raw_socket(&self) -> RawSocket {
-        *self.as_inner().socket().as_inner()
+        self.as_inner().socket().as_raw_socket()
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRawSocket for net::TcpListener {
     #[inline]
     fn as_raw_socket(&self) -> RawSocket {
-        *self.as_inner().socket().as_inner()
+        self.as_inner().socket().as_raw_socket()
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRawSocket for net::UdpSocket {
     #[inline]
     fn as_raw_socket(&self) -> RawSocket {
-        *self.as_inner().socket().as_inner()
+        self.as_inner().socket().as_raw_socket()
     }
 }
 
@@ -188,7 +191,7 @@ impl AsRawSocket for net::UdpSocket {
 impl FromRawSocket for net::TcpStream {
     #[inline]
     unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
-        let sock = sys::net::Socket::from_inner(sock);
+        let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
         net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
     }
 }
@@ -196,7 +199,7 @@ impl FromRawSocket for net::TcpStream {
 impl FromRawSocket for net::TcpListener {
     #[inline]
     unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
-        let sock = sys::net::Socket::from_inner(sock);
+        let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
         net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
     }
 }
@@ -204,7 +207,7 @@ impl FromRawSocket for net::TcpListener {
 impl FromRawSocket for net::UdpSocket {
     #[inline]
     unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
-        let sock = sys::net::Socket::from_inner(sock);
+        let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
         net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
     }
 }
@@ -213,7 +216,7 @@ impl FromRawSocket for net::UdpSocket {
 impl IntoRawSocket for net::TcpStream {
     #[inline]
     fn into_raw_socket(self) -> RawSocket {
-        self.into_inner().into_socket().into_inner()
+        self.into_inner().into_socket().into_inner().into_raw_socket()
     }
 }
 
@@ -221,7 +224,7 @@ impl IntoRawSocket for net::TcpStream {
 impl IntoRawSocket for net::TcpListener {
     #[inline]
     fn into_raw_socket(self) -> RawSocket {
-        self.into_inner().into_socket().into_inner()
+        self.into_inner().into_socket().into_inner().into_raw_socket()
     }
 }
 
@@ -229,6 +232,6 @@ impl IntoRawSocket for net::TcpListener {
 impl IntoRawSocket for net::UdpSocket {
     #[inline]
     fn into_raw_socket(self) -> RawSocket {
-        self.into_inner().into_socket().into_inner()
+        self.into_inner().into_socket().into_inner().into_raw_socket()
     }
 }
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
new file mode 100644
index 00000000000..23db66df09f
--- /dev/null
+++ b/library/std/src/os/windows/io/socket.rs
@@ -0,0 +1,216 @@
+//! Owned and borrowed OS sockets.
+
+#![unstable(feature = "io_safety", issue = "87074")]
+
+use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::forget;
+use crate::sys::c;
+
+/// A borrowed socket.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the socket.
+///
+/// This uses `repr(transparent)` and has the representation of a host socket,
+/// so it can be used in FFI in places where a socket is passed as an argument,
+/// it is not captured or consumed, and it never has the value
+/// `INVALID_SOCKET`.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
+#[cfg_attr(
+    target_pointer_width = "64",
+    rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
+)]
+#[unstable(feature = "io_safety", issue = "87074")]
+pub struct BorrowedSocket<'socket> {
+    socket: RawSocket,
+    _phantom: PhantomData<&'socket OwnedSocket>,
+}
+
+/// An owned socket.
+///
+/// This closes the socket on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host socket,
+/// so it can be used in FFI in places where a socket is passed as a consumed
+/// argument or returned as an owned value, and it never has the value
+/// `INVALID_SOCKET`.
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
+#[cfg_attr(
+    target_pointer_width = "64",
+    rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
+)]
+#[unstable(feature = "io_safety", issue = "87074")]
+pub struct OwnedSocket {
+    socket: RawSocket,
+}
+
+impl BorrowedSocket<'_> {
+    /// Return a `BorrowedSocket` holding the given raw socket.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `raw` must remain open for the duration of
+    /// the returned `BorrowedSocket`, and it must not have the value
+    /// `INVALID_SOCKET`.
+    #[inline]
+    #[unstable(feature = "io_safety", issue = "87074")]
+    pub unsafe fn borrow_raw_socket(socket: RawSocket) -> Self {
+        debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
+        Self { socket, _phantom: PhantomData }
+    }
+}
+
+impl AsRawSocket for BorrowedSocket<'_> {
+    #[inline]
+    fn as_raw_socket(&self) -> RawSocket {
+        self.socket
+    }
+}
+
+impl AsRawSocket for OwnedSocket {
+    #[inline]
+    fn as_raw_socket(&self) -> RawSocket {
+        self.socket
+    }
+}
+
+impl IntoRawSocket for OwnedSocket {
+    #[inline]
+    fn into_raw_socket(self) -> RawSocket {
+        let socket = self.socket;
+        forget(self);
+        socket
+    }
+}
+
+impl FromRawSocket for OwnedSocket {
+    /// Constructs a new instance of `Self` from the given raw socket.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `socket` must be open and suitable for
+    /// assuming ownership. The resource must not require cleanup other than
+    /// `closesocket`.
+    #[inline]
+    unsafe fn from_raw_socket(socket: RawSocket) -> Self {
+        debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
+        Self { socket }
+    }
+}
+
+impl Drop for OwnedSocket {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            let _ = c::closesocket(self.socket);
+        }
+    }
+}
+
+impl fmt::Debug for BorrowedSocket<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("BorrowedSocket").field("socket", &self.socket).finish()
+    }
+}
+
+impl fmt::Debug for OwnedSocket {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OwnedSocket").field("socket", &self.socket).finish()
+    }
+}
+
+/// A trait to borrow the socket from an underlying object.
+#[unstable(feature = "io_safety", issue = "87074")]
+pub trait AsSocket {
+    /// Borrows the socket.
+    fn as_socket(&self) -> BorrowedSocket<'_>;
+}
+
+impl AsSocket for BorrowedSocket<'_> {
+    #[inline]
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        *self
+    }
+}
+
+impl AsSocket for OwnedSocket {
+    #[inline]
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity
+        // invariants, and the `BorrowdSocket` is bounded by the lifetime
+        // of `&self`.
+        unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
+    }
+}
+
+impl AsSocket for crate::net::TcpStream {
+    #[inline]
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
+    }
+}
+
+impl From<crate::net::TcpStream> for OwnedSocket {
+    #[inline]
+    fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket {
+        unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) }
+    }
+}
+
+impl From<OwnedSocket> for crate::net::TcpStream {
+    #[inline]
+    fn from(owned: OwnedSocket) -> Self {
+        unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+    }
+}
+
+impl AsSocket for crate::net::TcpListener {
+    #[inline]
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
+    }
+}
+
+impl From<crate::net::TcpListener> for OwnedSocket {
+    #[inline]
+    fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket {
+        unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) }
+    }
+}
+
+impl From<OwnedSocket> for crate::net::TcpListener {
+    #[inline]
+    fn from(owned: OwnedSocket) -> Self {
+        unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+    }
+}
+
+impl AsSocket for crate::net::UdpSocket {
+    #[inline]
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
+    }
+}
+
+impl From<crate::net::UdpSocket> for OwnedSocket {
+    #[inline]
+    fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket {
+        unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) }
+    }
+}
+
+impl From<OwnedSocket> for crate::net::UdpSocket {
+    #[inline]
+    fn from(owned: OwnedSocket) -> Self {
+        unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+    }
+}
diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs
index 52ac508f9f7..969054dd3b3 100644
--- a/library/std/src/os/windows/mod.rs
+++ b/library/std/src/os/windows/mod.rs
@@ -32,8 +32,11 @@ pub mod prelude {
     pub use super::fs::{MetadataExt, OpenOptionsExt};
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
+    pub use super::io::{
+        AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, FromRawHandle, FromRawSocket,
+        HandleOrInvalid, IntoRawHandle, IntoRawSocket, OwnedHandle, OwnedSocket,
+    };
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket};
+    pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
 }
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 9e7ccd015b6..b246599dfc0 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -3,7 +3,9 @@
 #![stable(feature = "process_extensions", since = "1.2.0")]
 
 use crate::ffi::OsStr;
-use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
+use crate::os::windows::io::{
+    AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
+};
 use crate::process;
 use crate::sealed::Sealed;
 use crate::sys;
@@ -12,7 +14,16 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 #[stable(feature = "process_extensions", since = "1.2.0")]
 impl FromRawHandle for process::Stdio {
     unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
-        let handle = sys::handle::Handle::new(handle as *mut _);
+        let handle = sys::handle::Handle::from_raw_handle(handle as *mut _);
+        let io = sys::process::Stdio::Handle(handle);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<OwnedHandle> for process::Stdio {
+    fn from(handle: OwnedHandle) -> process::Stdio {
+        let handle = sys::handle::Handle::from_inner(handle);
         let io = sys::process::Stdio::Handle(handle);
         process::Stdio::from_inner(io)
     }
@@ -22,14 +33,29 @@ impl FromRawHandle for process::Stdio {
 impl AsRawHandle for process::Child {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
+        self.as_inner().handle().as_raw_handle() as *mut _
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsHandle for process::Child {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        self.as_inner().handle().as_handle()
     }
 }
 
 #[stable(feature = "into_raw_os", since = "1.4.0")]
 impl IntoRawHandle for process::Child {
     fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
+        self.into_inner().into_handle().into_raw_handle() as *mut _
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl From<process::Child> for OwnedHandle {
+    fn from(child: process::Child) -> OwnedHandle {
+        child.into_inner().into_handle().into_inner()
     }
 }
 
@@ -37,7 +63,7 @@ impl IntoRawHandle for process::Child {
 impl AsRawHandle for process::ChildStdin {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
+        self.as_inner().handle().as_raw_handle() as *mut _
     }
 }
 
@@ -45,7 +71,7 @@ impl AsRawHandle for process::ChildStdin {
 impl AsRawHandle for process::ChildStdout {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
+        self.as_inner().handle().as_raw_handle() as *mut _
     }
 }
 
@@ -53,28 +79,28 @@ impl AsRawHandle for process::ChildStdout {
 impl AsRawHandle for process::ChildStderr {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
+        self.as_inner().handle().as_raw_handle() as *mut _
     }
 }
 
 #[stable(feature = "into_raw_os", since = "1.4.0")]
 impl IntoRawHandle for process::ChildStdin {
     fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
+        self.into_inner().into_handle().into_raw_handle() as *mut _
     }
 }
 
 #[stable(feature = "into_raw_os", since = "1.4.0")]
 impl IntoRawHandle for process::ChildStdout {
     fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
+        self.into_inner().into_handle().into_raw_handle() as *mut _
     }
 }
 
 #[stable(feature = "into_raw_os", since = "1.4.0")]
 impl IntoRawHandle for process::ChildStderr {
     fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
+        self.into_inner().into_handle().into_raw_handle() as *mut _
     }
 }
 
diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs
index 6bd02054f71..fb1bf66ceed 100644
--- a/library/std/src/os/windows/thread.rs
+++ b/library/std/src/os/windows/thread.rs
@@ -10,7 +10,7 @@ use crate::thread;
 impl<T> AsRawHandle for thread::JoinHandle<T> {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
+        self.as_inner().handle().as_raw_handle() as *mut _
     }
 }
 
@@ -18,6 +18,6 @@ impl<T> AsRawHandle for thread::JoinHandle<T> {
 impl<T> IntoRawHandle for thread::JoinHandle<T> {
     #[inline]
     fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
+        self.into_inner().into_handle().into_raw_handle() as *mut _
     }
 }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 69419145b1b..2a9c361c18a 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -315,7 +315,7 @@ fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool {
 }
 
 // basic workhorse for splitting stem and extension
-fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
+fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
     if os_str_as_u8_slice(file) == b".." {
         return (Some(file), None);
     }
@@ -334,6 +334,25 @@ fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
     }
 }
 
+fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
+    let slice = os_str_as_u8_slice(file);
+    if slice == b".." {
+        return (file, None);
+    }
+
+    // The unsafety here stems from converting between &OsStr and &[u8]
+    // and back. This is safe to do because (1) we only look at ASCII
+    // contents of the encoding and (2) new &OsStr values are produced
+    // only from ASCII-bounded slices of existing &OsStr values.
+    let i = match slice[1..].iter().position(|b| *b == b'.') {
+        Some(i) => i + 1,
+        None => return (file, None),
+    };
+    let before = &slice[..i];
+    let after = &slice[i + 1..];
+    unsafe { (u8_slice_as_os_str(before), Some(u8_slice_as_os_str(after))) }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // The core iterators
 ////////////////////////////////////////////////////////////////////////////////
@@ -962,7 +981,7 @@ impl cmp::Eq for Components<'_> {}
 impl<'a> cmp::PartialOrd for Components<'a> {
     #[inline]
     fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
-        Iterator::partial_cmp(self.clone(), other.clone())
+        Some(compare_components(self.clone(), other.clone()))
     }
 }
 
@@ -970,8 +989,41 @@ impl<'a> cmp::PartialOrd for Components<'a> {
 impl cmp::Ord for Components<'_> {
     #[inline]
     fn cmp(&self, other: &Self) -> cmp::Ordering {
-        Iterator::cmp(self.clone(), other.clone())
+        compare_components(self.clone(), other.clone())
+    }
+}
+
+fn compare_components(mut left: Components<'_>, mut right: Components<'_>) -> cmp::Ordering {
+    // Fast path for long shared prefixes
+    //
+    // - compare raw bytes to find first mismatch
+    // - backtrack to find separator before mismatch to avoid ambiguous parsings of '.' or '..' characters
+    // - if found update state to only do a component-wise comparison on the remainder,
+    //   otherwise do it on the full path
+    //
+    // The fast path isn't taken for paths with a PrefixComponent to avoid backtracking into
+    // the middle of one
+    if left.prefix.is_none() && right.prefix.is_none() && left.front == right.front {
+        // this might benefit from a [u8]::first_mismatch simd implementation, if it existed
+        let first_difference =
+            match left.path.iter().zip(right.path.iter()).position(|(&a, &b)| a != b) {
+                None if left.path.len() == right.path.len() => return cmp::Ordering::Equal,
+                None => left.path.len().min(right.path.len()),
+                Some(diff) => diff,
+            };
+
+        if let Some(previous_sep) =
+            left.path[..first_difference].iter().rposition(|&b| left.is_sep_byte(b))
+        {
+            let mismatched_component_start = previous_sep + 1;
+            left.path = &left.path[mismatched_component_start..];
+            left.front = State::Body;
+            right.path = &right.path[mismatched_component_start..];
+            right.front = State::Body;
+        }
     }
+
+    Iterator::cmp(left, right)
 }
 
 /// An iterator over [`Path`] and its ancestors.
@@ -1704,7 +1756,7 @@ impl cmp::Eq for PathBuf {}
 impl cmp::PartialOrd for PathBuf {
     #[inline]
     fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
-        self.components().partial_cmp(other.components())
+        Some(compare_components(self.components(), other.components()))
     }
 }
 
@@ -1712,7 +1764,7 @@ impl cmp::PartialOrd for PathBuf {
 impl cmp::Ord for PathBuf {
     #[inline]
     fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
-        self.components().cmp(other.components())
+        compare_components(self.components(), other.components())
     }
 }
 
@@ -2180,9 +2232,49 @@ impl Path {
     /// assert_eq!("foo", Path::new("foo.rs").file_stem().unwrap());
     /// assert_eq!("foo.tar", Path::new("foo.tar.gz").file_stem().unwrap());
     /// ```
+    ///
+    /// # See Also
+    /// This method is similar to [`Path::file_prefix`], which extracts the portion of the file name
+    /// before the *first* `.`
+    ///
+    /// [`Path::file_prefix`]: Path::file_prefix
+    ///
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn file_stem(&self) -> Option<&OsStr> {
-        self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
+        self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after))
+    }
+
+    /// Extracts the prefix of [`self.file_name`].
+    ///
+    /// The prefix is:
+    ///
+    /// * [`None`], if there is no file name;
+    /// * The entire file name if there is no embedded `.`;
+    /// * The portion of the file name before the first non-beginning `.`;
+    /// * The entire file name if the file name begins with `.` and has no other `.`s within;
+    /// * The portion of the file name before the second `.` if the file name begins with `.`
+    ///
+    /// [`self.file_name`]: Path::file_name
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(path_file_prefix)]
+    /// use std::path::Path;
+    ///
+    /// assert_eq!("foo", Path::new("foo.rs").file_prefix().unwrap());
+    /// assert_eq!("foo", Path::new("foo.tar.gz").file_prefix().unwrap());
+    /// ```
+    ///
+    /// # See Also
+    /// This method is similar to [`Path::file_stem`], which extracts the portion of the file name
+    /// before the *last* `.`
+    ///
+    /// [`Path::file_stem`]: Path::file_stem
+    ///
+    #[unstable(feature = "path_file_prefix", issue = "86319")]
+    pub fn file_prefix(&self) -> Option<&OsStr> {
+        self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before))
     }
 
     /// Extracts the extension of [`self.file_name`], if possible.
@@ -2206,7 +2298,7 @@ impl Path {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn extension(&self) -> Option<&OsStr> {
-        self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
+        self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after))
     }
 
     /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
@@ -2686,7 +2778,7 @@ impl fmt::Display for Display<'_> {
 impl cmp::PartialEq for Path {
     #[inline]
     fn eq(&self, other: &Path) -> bool {
-        self.components().eq(other.components())
+        self.components() == other.components()
     }
 }
 
@@ -2706,7 +2798,7 @@ impl cmp::Eq for Path {}
 impl cmp::PartialOrd for Path {
     #[inline]
     fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
-        self.components().partial_cmp(other.components())
+        Some(compare_components(self.components(), other.components()))
     }
 }
 
@@ -2714,7 +2806,7 @@ impl cmp::PartialOrd for Path {
 impl cmp::Ord for Path {
     #[inline]
     fn cmp(&self, other: &Path) -> cmp::Ordering {
-        self.components().cmp(other.components())
+        compare_components(self.components(), other.components())
     }
 }
 
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 896d6c2a64c..ce23cf6cd21 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -1,9 +1,11 @@
 use super::*;
 
+use crate::collections::BTreeSet;
 use crate::rc::Rc;
 use crate::sync::Arc;
+use core::hint::black_box;
 
-macro_rules! t(
+macro_rules! t (
     ($path:expr, iter: $iter:expr) => (
         {
             let path = Path::new($path);
@@ -73,15 +75,33 @@ macro_rules! t(
         }
     );
 
+    ($path:expr, file_prefix: $file_prefix:expr, extension: $extension:expr) => (
+        {
+            let path = Path::new($path);
+
+            let prefix = path.file_prefix().map(|p| p.to_str().unwrap());
+            let exp_prefix: Option<&str> = $file_prefix;
+            assert!(prefix == exp_prefix, "file_prefix: Expected {:?}, found {:?}",
+                    exp_prefix, prefix);
+
+            let ext = path.extension().map(|p| p.to_str().unwrap());
+            let exp_ext: Option<&str> = $extension;
+            assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
+                    exp_ext, ext);
+        }
+    );
+
     ($path:expr, iter: $iter:expr,
                  has_root: $has_root:expr, is_absolute: $is_absolute:expr,
                  parent: $parent:expr, file_name: $file:expr,
-                 file_stem: $file_stem:expr, extension: $extension:expr) => (
+                 file_stem: $file_stem:expr, extension: $extension:expr,
+                 file_prefix: $file_prefix:expr) => (
         {
             t!($path, iter: $iter);
             t!($path, has_root: $has_root, is_absolute: $is_absolute);
             t!($path, parent: $parent, file_name: $file);
             t!($path, file_stem: $file_stem, extension: $extension);
+            t!($path, file_prefix: $file_prefix, extension: $extension);
         }
     );
 );
@@ -116,7 +136,8 @@ pub fn test_decompositions_unix() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo",
@@ -126,7 +147,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/",
@@ -136,7 +158,8 @@ pub fn test_decompositions_unix() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/foo",
@@ -146,7 +169,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/",
@@ -156,7 +180,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/foo/",
@@ -166,7 +191,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/bar",
@@ -176,7 +202,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("/foo/bar",
@@ -186,7 +213,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("///foo///",
@@ -196,7 +224,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("///foo///bar",
@@ -206,7 +235,8 @@ pub fn test_decompositions_unix() {
     parent: Some("///foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./.",
@@ -216,7 +246,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/..",
@@ -226,7 +257,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("../",
@@ -236,7 +268,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/.",
@@ -246,7 +279,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/..",
@@ -256,7 +290,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/./",
@@ -266,7 +301,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/./bar",
@@ -276,7 +312,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("foo/../",
@@ -286,7 +323,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/../bar",
@@ -296,7 +334,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo/.."),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./a",
@@ -306,7 +345,8 @@ pub fn test_decompositions_unix() {
     parent: Some("."),
     file_name: Some("a"),
     file_stem: Some("a"),
-    extension: None
+    extension: None,
+    file_prefix: Some("a")
     );
 
     t!(".",
@@ -316,7 +356,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("./",
@@ -326,7 +367,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("a/b",
@@ -336,7 +378,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a//b",
@@ -346,7 +389,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/./b",
@@ -356,7 +400,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/b/c",
@@ -366,7 +411,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a/b"),
     file_name: Some("c"),
     file_stem: Some("c"),
-    extension: None
+    extension: None,
+    file_prefix: Some("c")
     );
 
     t!(".foo",
@@ -376,7 +422,41 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some(".foo"),
     file_stem: Some(".foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some(".foo")
+    );
+
+    t!("a/.foo",
+    iter: ["a", ".foo"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".foo"),
+    file_stem: Some(".foo"),
+    extension: None,
+    file_prefix: Some(".foo")
+    );
+
+    t!("a/.rustfmt.toml",
+    iter: ["a", ".rustfmt.toml"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".rustfmt.toml"),
+    file_stem: Some(".rustfmt"),
+    extension: Some("toml"),
+    file_prefix: Some(".rustfmt")
+    );
+
+    t!("a/.x.y.z",
+    iter: ["a", ".x.y.z"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".x.y.z"),
+    file_stem: Some(".x.y"),
+    extension: Some("z"),
+    file_prefix: Some(".x")
     );
 }
 
@@ -390,7 +470,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo",
@@ -400,7 +481,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/",
@@ -410,7 +492,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\",
@@ -420,7 +503,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("c:",
@@ -430,7 +514,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("c:\\",
@@ -440,7 +525,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("c:/",
@@ -450,7 +536,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/foo",
@@ -460,7 +547,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/",
@@ -470,7 +558,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/foo/",
@@ -480,7 +569,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/bar",
@@ -490,7 +580,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("/foo/bar",
@@ -500,7 +591,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("///foo///",
@@ -510,7 +602,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("///foo///bar",
@@ -520,7 +613,8 @@ pub fn test_decompositions_windows() {
     parent: Some("///foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./.",
@@ -530,7 +624,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/..",
@@ -540,7 +635,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("../",
@@ -550,7 +646,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/.",
@@ -560,7 +657,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/..",
@@ -570,7 +668,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/./",
@@ -580,7 +679,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/./bar",
@@ -590,7 +690,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("foo/../",
@@ -600,7 +701,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/../bar",
@@ -610,7 +712,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo/.."),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./a",
@@ -620,7 +723,8 @@ pub fn test_decompositions_windows() {
     parent: Some("."),
     file_name: Some("a"),
     file_stem: Some("a"),
-    extension: None
+    extension: None,
+    file_prefix: Some("a")
     );
 
     t!(".",
@@ -630,7 +734,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("./",
@@ -640,7 +745,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("a/b",
@@ -650,7 +756,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a//b",
@@ -660,7 +767,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/./b",
@@ -670,7 +778,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/b/c",
@@ -680,7 +789,9 @@ pub fn test_decompositions_windows() {
        parent: Some("a/b"),
        file_name: Some("c"),
        file_stem: Some("c"),
-       extension: None);
+       extension: None,
+       file_prefix: Some("c")
+    );
 
     t!("a\\b\\c",
     iter: ["a", "b", "c"],
@@ -689,7 +800,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a\\b"),
     file_name: Some("c"),
     file_stem: Some("c"),
-    extension: None
+    extension: None,
+    file_prefix: Some("c")
     );
 
     t!("\\a",
@@ -699,7 +811,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\"),
     file_name: Some("a"),
     file_stem: Some("a"),
-    extension: None
+    extension: None,
+    file_prefix: Some("a")
     );
 
     t!("c:\\foo.txt",
@@ -709,7 +822,8 @@ pub fn test_decompositions_windows() {
     parent: Some("c:\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\server\\share\\foo.txt",
@@ -719,7 +833,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\server\\share\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\server\\share",
@@ -729,7 +844,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\server",
@@ -739,7 +855,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\"),
     file_name: Some("server"),
     file_stem: Some("server"),
-    extension: None
+    extension: None,
+    file_prefix: Some("server")
     );
 
     t!("\\\\?\\bar\\foo.txt",
@@ -749,7 +866,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\bar\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\?\\bar",
@@ -759,7 +877,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\",
@@ -769,7 +888,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\UNC\\server\\share\\foo.txt",
@@ -779,7 +899,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\UNC\\server\\share\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\?\\UNC\\server",
@@ -789,7 +910,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\UNC\\",
@@ -799,7 +921,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\C:\\foo.txt",
@@ -809,7 +932,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\C:\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\?\\C:\\",
@@ -819,7 +943,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\C:",
@@ -829,7 +954,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\foo/bar",
@@ -839,7 +965,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\C:/foo",
@@ -849,7 +976,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\.\\foo\\bar",
@@ -859,7 +987,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\.\\foo\\"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("\\\\.\\foo",
@@ -869,7 +998,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\.\\foo/bar",
@@ -879,7 +1009,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\.\\foo/"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("\\\\.\\foo\\bar/baz",
@@ -889,7 +1020,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\.\\foo\\bar"),
     file_name: Some("baz"),
     file_stem: Some("baz"),
-    extension: None
+    extension: None,
+    file_prefix: Some("baz")
     );
 
     t!("\\\\.\\",
@@ -899,7 +1031,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\a\\b\\",
@@ -909,7 +1042,52 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\a\\"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
+    );
+
+    t!("\\\\?\\C:\\foo.txt.zip",
+    iter: ["\\\\?\\C:", "\\", "foo.txt.zip"],
+    has_root: true,
+    is_absolute: true,
+    parent: Some("\\\\?\\C:\\"),
+    file_name: Some("foo.txt.zip"),
+    file_stem: Some("foo.txt"),
+    extension: Some("zip"),
+    file_prefix: Some("foo")
+    );
+
+    t!("\\\\?\\C:\\.foo.txt.zip",
+    iter: ["\\\\?\\C:", "\\", ".foo.txt.zip"],
+    has_root: true,
+    is_absolute: true,
+    parent: Some("\\\\?\\C:\\"),
+    file_name: Some(".foo.txt.zip"),
+    file_stem: Some(".foo.txt"),
+    extension: Some("zip"),
+    file_prefix: Some(".foo")
+    );
+
+    t!("\\\\?\\C:\\.foo",
+    iter: ["\\\\?\\C:", "\\", ".foo"],
+    has_root: true,
+    is_absolute: true,
+    parent: Some("\\\\?\\C:\\"),
+    file_name: Some(".foo"),
+    file_stem: Some(".foo"),
+    extension: None,
+    file_prefix: Some(".foo")
+    );
+
+    t!("a/.x.y.z",
+    iter: ["a", ".x.y.z"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".x.y.z"),
+    file_stem: Some(".x.y"),
+    extension: Some("z"),
+    file_prefix: Some(".x")
     );
 }
 
@@ -949,12 +1127,59 @@ pub fn test_stem_ext() {
 
     t!("..", file_stem: None, extension: None);
 
+    t!(".x.y.z", file_stem: Some(".x.y"), extension: Some("z"));
+
+    t!("..x.y.z", file_stem: Some("..x.y"), extension: Some("z"));
+
     t!("", file_stem: None, extension: None);
 }
 
 #[test]
+pub fn test_prefix_ext() {
+    t!("foo",
+    file_prefix: Some("foo"),
+    extension: None
+    );
+
+    t!("foo.",
+    file_prefix: Some("foo"),
+    extension: Some("")
+    );
+
+    t!(".foo",
+    file_prefix: Some(".foo"),
+    extension: None
+    );
+
+    t!("foo.txt",
+    file_prefix: Some("foo"),
+    extension: Some("txt")
+    );
+
+    t!("foo.bar.txt",
+    file_prefix: Some("foo"),
+    extension: Some("txt")
+    );
+
+    t!("foo.bar.",
+    file_prefix: Some("foo"),
+    extension: Some("")
+    );
+
+    t!(".", file_prefix: None, extension: None);
+
+    t!("..", file_prefix: None, extension: None);
+
+    t!(".x.y.z", file_prefix: Some(".x"), extension: Some("z"));
+
+    t!("..x.y.z", file_prefix: Some("."), extension: Some("z"));
+
+    t!("", file_prefix: None, extension: None);
+}
+
+#[test]
 pub fn test_push() {
-    macro_rules! tp(
+    macro_rules! tp (
         ($path:expr, $push:expr, $expected:expr) => ( {
             let mut actual = PathBuf::from($path);
             actual.push($push);
@@ -1042,7 +1267,7 @@ pub fn test_push() {
 
 #[test]
 pub fn test_pop() {
-    macro_rules! tp(
+    macro_rules! tp (
         ($path:expr, $expected:expr, $output:expr) => ( {
             let mut actual = PathBuf::from($path);
             let output = actual.pop();
@@ -1096,7 +1321,7 @@ pub fn test_pop() {
 
 #[test]
 pub fn test_set_file_name() {
-    macro_rules! tfn(
+    macro_rules! tfn (
             ($path:expr, $file:expr, $expected:expr) => ( {
             let mut p = PathBuf::from($path);
             p.set_file_name($file);
@@ -1130,7 +1355,7 @@ pub fn test_set_file_name() {
 
 #[test]
 pub fn test_set_extension() {
-    macro_rules! tfe(
+    macro_rules! tfe (
             ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
             let mut p = PathBuf::from($path);
             let output = p.set_extension($ext);
@@ -1192,7 +1417,7 @@ pub fn test_compare() {
         s.finish()
     }
 
-    macro_rules! tc(
+    macro_rules! tc (
         ($path1:expr, $path2:expr, eq: $eq:expr,
          starts_with: $starts_with:expr, ends_with: $ends_with:expr,
          relative_from: $relative_from:expr) => ({
@@ -1392,3 +1617,69 @@ fn into_rc() {
     assert_eq!(&*rc2, path);
     assert_eq!(&*arc2, path);
 }
+
+#[test]
+fn test_ord() {
+    macro_rules! ord(
+        ($ord:ident, $left:expr, $right:expr) => ( {
+            assert_eq!(Path::new($left).cmp(&Path::new($right)), core::cmp::Ordering::$ord);
+        });
+    );
+
+    ord!(Less, "1", "2");
+    ord!(Less, "/foo/bar", "/foo./bar");
+    ord!(Less, "foo/bar", "foo/bar.");
+    ord!(Equal, "foo/./bar", "foo/bar/");
+    ord!(Equal, "foo/bar", "foo/bar/");
+    ord!(Equal, "foo/bar", "foo/bar/.");
+    ord!(Equal, "foo/bar", "foo/bar//");
+}
+
+#[bench]
+fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
+    let prefix = "my/home";
+    let mut paths: Vec<_> =
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+
+    paths.sort();
+
+    b.iter(|| {
+        black_box(paths.as_mut_slice()).sort_unstable();
+    });
+}
+
+#[bench]
+fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
+    let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
+    let paths: Vec<_> =
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+
+    let mut set = BTreeSet::new();
+
+    paths.iter().for_each(|p| {
+        set.insert(p.as_path());
+    });
+
+    b.iter(|| {
+        set.remove(paths[500].as_path());
+        set.insert(paths[500].as_path());
+    });
+}
+
+#[bench]
+fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
+    let prefix = "my/home";
+    let paths: Vec<_> =
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+
+    let mut set = BTreeSet::new();
+
+    paths.iter().for_each(|p| {
+        set.insert(p.as_path());
+    });
+
+    b.iter(|| {
+        set.remove(paths[500].as_path());
+        set.insert(paths[500].as_path());
+    });
+}
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index f5ce5210f81..c9b21fcf9c6 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -258,6 +258,12 @@ pub struct ChildStdin {
     inner: AnonPipe,
 }
 
+// In addition to the `impl`s here, `ChildStdin` also has `impl`s for
+// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
+// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
+// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
+// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
+
 #[stable(feature = "process", since = "1.0.0")]
 impl Write for ChildStdin {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
@@ -335,6 +341,12 @@ pub struct ChildStdout {
     inner: AnonPipe,
 }
 
+// In addition to the `impl`s here, `ChildStdout` also has `impl`s for
+// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
+// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
+// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
+// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
+
 #[stable(feature = "process", since = "1.0.0")]
 impl Read for ChildStdout {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -396,6 +408,12 @@ pub struct ChildStderr {
     inner: AnonPipe,
 }
 
+// In addition to the `impl`s here, `ChildStderr` also has `impl`s for
+// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
+// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
+// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
+// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
+
 #[stable(feature = "process", since = "1.0.0")]
 impl Read for ChildStderr {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 28e32681e15..0956726084e 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -5,21 +5,14 @@ mod tests;
 
 use crate::cmp;
 use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
-use crate::mem;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::sys::cvt;
-use crate::sys_common::AsInner;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 use libc::{c_int, c_void};
 
 #[derive(Debug)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
-// 32-bit c_int. Below is -2, in two's complement, but that only works out
-// because c_int is 32 bits.
-#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
-pub struct FileDesc {
-    fd: c_int,
-}
+pub struct FileDesc(OwnedFd);
 
 // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
 // with the man page quoting that if the count of bytes to read is
@@ -67,26 +60,13 @@ const fn max_iov() -> usize {
 }
 
 impl FileDesc {
-    pub fn new(fd: c_int) -> FileDesc {
-        assert_ne!(fd, -1i32);
-        // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
-        unsafe { FileDesc { fd } }
-    }
-
-    pub fn raw(&self) -> c_int {
-        self.fd
-    }
-
-    /// Extracts the actual file descriptor without closing it.
-    pub fn into_raw(self) -> c_int {
-        let fd = self.fd;
-        mem::forget(self);
-        fd
-    }
-
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
-            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
+            libc::read(
+                self.as_raw_fd(),
+                buf.as_mut_ptr() as *mut c_void,
+                cmp::min(buf.len(), READ_LIMIT),
+            )
         })?;
         Ok(ret as usize)
     }
@@ -95,7 +75,7 @@ impl FileDesc {
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::readv(
-                self.fd,
+                self.as_raw_fd(),
                 bufs.as_ptr() as *const libc::iovec,
                 cmp::min(bufs.len(), max_iov()) as c_int,
             )
@@ -138,7 +118,7 @@ impl FileDesc {
 
         unsafe {
             cvt_pread64(
-                self.fd,
+                self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut c_void,
                 cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
@@ -149,7 +129,11 @@ impl FileDesc {
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
-            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
+            libc::write(
+                self.as_raw_fd(),
+                buf.as_ptr() as *const c_void,
+                cmp::min(buf.len(), READ_LIMIT),
+            )
         })?;
         Ok(ret as usize)
     }
@@ -158,7 +142,7 @@ impl FileDesc {
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::writev(
-                self.fd,
+                self.as_raw_fd(),
                 bufs.as_ptr() as *const libc::iovec,
                 cmp::min(bufs.len(), max_iov()) as c_int,
             )
@@ -196,7 +180,7 @@ impl FileDesc {
 
         unsafe {
             cvt_pwrite64(
-                self.fd,
+                self.as_raw_fd(),
                 buf.as_ptr() as *const c_void,
                 cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
@@ -207,7 +191,7 @@ impl FileDesc {
 
     #[cfg(target_os = "linux")]
     pub fn get_cloexec(&self) -> io::Result<bool> {
-        unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
+        unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
     }
 
     #[cfg(not(any(
@@ -224,7 +208,7 @@ impl FileDesc {
     )))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
-            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
+            cvt(libc::ioctl(self.as_raw_fd(), libc::FIOCLEX))?;
             Ok(())
         }
     }
@@ -242,10 +226,10 @@ impl FileDesc {
     ))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
-            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
+            let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))?;
             let new = previous | libc::FD_CLOEXEC;
             if new != previous {
-                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
+                cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFD, new))?;
             }
             Ok(())
         }
@@ -261,7 +245,7 @@ impl FileDesc {
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         unsafe {
             let v = nonblocking as c_int;
-            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
+            cvt(libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &v))?;
             Ok(())
         }
     }
@@ -269,14 +253,14 @@ impl FileDesc {
     #[cfg(not(target_os = "linux"))]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         unsafe {
-            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
+            let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFL))?;
             let new = if nonblocking {
                 previous | libc::O_NONBLOCK
             } else {
                 previous & !libc::O_NONBLOCK
             };
             if new != previous {
-                cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
+                cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFL, new))?;
             }
             Ok(())
         }
@@ -296,8 +280,8 @@ impl FileDesc {
         #[cfg(target_os = "espidf")]
         let cmd = libc::F_DUPFD;
 
-        let fd = cvt(unsafe { libc::fcntl(self.raw(), cmd, 0) })?;
-        Ok(FileDesc::new(fd))
+        let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
+        Ok(unsafe { FileDesc::from_raw_fd(fd) })
     }
 }
 
@@ -312,19 +296,44 @@ impl<'a> Read for &'a FileDesc {
     }
 }
 
-impl AsInner<c_int> for FileDesc {
-    fn as_inner(&self) -> &c_int {
-        &self.fd
+impl AsInner<OwnedFd> for FileDesc {
+    fn as_inner(&self) -> &OwnedFd {
+        &self.0
+    }
+}
+
+impl IntoInner<OwnedFd> for FileDesc {
+    fn into_inner(self) -> OwnedFd {
+        self.0
+    }
+}
+
+impl FromInner<OwnedFd> for FileDesc {
+    fn from_inner(owned_fd: OwnedFd) -> Self {
+        Self(owned_fd)
+    }
+}
+
+impl AsFd for FileDesc {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for FileDesc {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for FileDesc {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
     }
 }
 
-impl Drop for FileDesc {
-    fn drop(&mut self) {
-        // Note that errors are ignored when closing a file descriptor. The
-        // reason for this is that if an error occurs we don't actually know if
-        // the file descriptor was closed or not, and if we retried (for
-        // something like EINTR), we might close another valid file descriptor
-        // opened after we closed ours.
-        let _ = unsafe { libc::close(self.fd) };
+impl FromRawFd for FileDesc {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FromRawFd::from_raw_fd(raw_fd))
     }
 }
diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs
index c9520485c3c..5d17e46786c 100644
--- a/library/std/src/sys/unix/fd/tests.rs
+++ b/library/std/src/sys/unix/fd/tests.rs
@@ -1,9 +1,10 @@
 use super::{FileDesc, IoSlice};
+use crate::os::unix::io::FromRawFd;
 use core::mem::ManuallyDrop;
 
 #[test]
 fn limit_vector_count() {
-    let stdout = ManuallyDrop::new(unsafe { FileDesc { fd: 1 } });
+    let stdout = ManuallyDrop::new(unsafe { FileDesc::from_raw_fd(1) });
     let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
     assert!(stdout.write_vectored(&bufs).is_ok());
 }
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index fd4defd72eb..6075eb5c7c5 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -4,13 +4,14 @@ use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sync::Arc;
 use crate::sys::fd::FileDesc;
 use crate::sys::time::SystemTime;
 use crate::sys::{cvt, cvt_r};
-use crate::sys_common::{AsInner, FromInner};
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 #[cfg(any(
     all(target_os = "linux", target_env = "gnu"),
@@ -764,11 +765,11 @@ impl File {
         // However, since this is a variadic function, C integer promotion rules mean that on
         // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms).
         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
-        Ok(File(FileDesc::new(fd)))
+        Ok(File(unsafe { FileDesc::from_raw_fd(fd) }))
     }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
-        let fd = self.0.raw();
+        let fd = self.as_raw_fd();
 
         cfg_has_statx! {
             if let Some(ret) = unsafe { try_statx(
@@ -787,7 +788,7 @@ impl File {
     }
 
     pub fn fsync(&self) -> io::Result<()> {
-        cvt_r(|| unsafe { os_fsync(self.0.raw()) })?;
+        cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?;
         return Ok(());
 
         #[cfg(any(target_os = "macos", target_os = "ios"))]
@@ -801,7 +802,7 @@ impl File {
     }
 
     pub fn datasync(&self) -> io::Result<()> {
-        cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
+        cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?;
         return Ok(());
 
         #[cfg(any(target_os = "macos", target_os = "ios"))]
@@ -834,14 +835,14 @@ impl File {
 
     pub fn truncate(&self, size: u64) -> io::Result<()> {
         #[cfg(target_os = "android")]
-        return crate::sys::android::ftruncate64(self.0.raw(), size);
+        return crate::sys::android::ftruncate64(self.as_raw_fd(), size);
 
         #[cfg(not(target_os = "android"))]
         {
             use crate::convert::TryInto;
             let size: off64_t =
                 size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
-            cvt_r(|| unsafe { ftruncate64(self.0.raw(), size) }).map(drop)
+            cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
         }
     }
 
@@ -891,7 +892,7 @@ impl File {
             SeekFrom::End(off) => (libc::SEEK_END, off),
             SeekFrom::Current(off) => (libc::SEEK_CUR, off),
         };
-        let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
+        let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos, whence) })?;
         Ok(n as u64)
     }
 
@@ -899,16 +900,8 @@ impl File {
         self.0.duplicate().map(File)
     }
 
-    pub fn fd(&self) -> &FileDesc {
-        &self.0
-    }
-
-    pub fn into_fd(self) -> FileDesc {
-        self.0
-    }
-
     pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
-        cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
+        cvt_r(|| unsafe { libc::fchmod(self.as_raw_fd(), perm.mode) })?;
         Ok(())
     }
 }
@@ -933,9 +926,51 @@ fn cstr(path: &Path) -> io::Result<CString> {
     Ok(CString::new(path.as_os_str().as_bytes())?)
 }
 
-impl FromInner<c_int> for File {
-    fn from_inner(fd: c_int) -> File {
-        File(FileDesc::new(fd))
+impl AsInner<FileDesc> for File {
+    fn as_inner(&self) -> &FileDesc {
+        &self.0
+    }
+}
+
+impl AsInnerMut<FileDesc> for File {
+    fn as_inner_mut(&mut self) -> &mut FileDesc {
+        &mut self.0
+    }
+}
+
+impl IntoInner<FileDesc> for File {
+    fn into_inner(self) -> FileDesc {
+        self.0
+    }
+}
+
+impl FromInner<FileDesc> for File {
+    fn from_inner(file_desc: FileDesc) -> Self {
+        Self(file_desc)
+    }
+}
+
+impl AsFd for File {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for File {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for File {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for File {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FromRawFd::from_raw_fd(raw_fd))
     }
 }
 
@@ -1009,7 +1044,7 @@ impl fmt::Debug for File {
             None
         }
 
-        let fd = self.0.raw();
+        let fd = self.as_raw_fd();
         let mut b = f.debug_struct("File");
         b.field("fd", &fd);
         if let Some(path) = get_path(fd) {
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 3f614fde08a..c2f5da1dbbb 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -3,6 +3,7 @@ use crate::ffi::CStr;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::net::{Shutdown, SocketAddr};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::str;
 use crate::sys::fd::FileDesc;
 use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
@@ -74,10 +75,10 @@ impl Socket {
                     // flag to atomically create the socket and set it as
                     // CLOEXEC. On Linux this was added in 2.6.27.
                     let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
-                    Ok(Socket(FileDesc::new(fd)))
+                    Ok(Socket(FileDesc::from_raw_fd(fd)))
                 } else {
                     let fd = cvt(libc::socket(fam, ty, 0))?;
-                    let fd = FileDesc::new(fd);
+                    let fd = FileDesc::from_raw_fd(fd);
                     fd.set_cloexec()?;
                     let socket = Socket(fd);
 
@@ -109,11 +110,11 @@ impl Socket {
                 ))] {
                     // Like above, set cloexec atomically
                     cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
-                    Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))))
+                    Ok((Socket(FileDesc::from_raw_fd(fds[0])), Socket(FileDesc::from_raw_fd(fds[1]))))
                 } else {
                     cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
-                    let a = FileDesc::new(fds[0]);
-                    let b = FileDesc::new(fds[1]);
+                    let a = FileDesc::from_raw_fd(fds[0]);
+                    let b = FileDesc::from_raw_fd(fds[1]);
                     a.set_cloexec()?;
                     b.set_cloexec()?;
                     Ok((Socket(a), Socket(b)))
@@ -131,7 +132,7 @@ impl Socket {
         self.set_nonblocking(true)?;
         let r = unsafe {
             let (addrp, len) = addr.into_inner();
-            cvt(libc::connect(self.0.raw(), addrp, len))
+            cvt(libc::connect(self.as_raw_fd(), addrp, len))
         };
         self.set_nonblocking(false)?;
 
@@ -142,7 +143,7 @@ impl Socket {
             Err(e) => return Err(e),
         }
 
-        let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 };
+        let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
 
         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
             return Err(io::Error::new_const(
@@ -212,15 +213,17 @@ impl Socket {
                 target_os = "netbsd",
                 target_os = "openbsd",
             ))] {
-                let fd = cvt_r(|| unsafe {
-                    libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
-                })?;
-                Ok(Socket(FileDesc::new(fd)))
+                unsafe {
+                    let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?;
+                    Ok(Socket(FileDesc::from_raw_fd(fd)))
+                }
             } else {
-                let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
-                let fd = FileDesc::new(fd);
-                fd.set_cloexec()?;
-                Ok(Socket(fd))
+                unsafe {
+                    let fd = cvt_r(|| libc::accept(self.as_raw_fd(), storage, len))?;
+                    let fd = FileDesc::from_raw_fd(fd);
+                    fd.set_cloexec()?;
+                    Ok(Socket(fd))
+                }
             }
         }
     }
@@ -231,7 +234,7 @@ impl Socket {
 
     fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
         let ret = cvt(unsafe {
-            libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
+            libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
         })?;
         Ok(ret as usize)
     }
@@ -263,7 +266,7 @@ impl Socket {
 
         let n = cvt(unsafe {
             libc::recvfrom(
-                self.0.raw(),
+                self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut c_void,
                 buf.len(),
                 flags,
@@ -288,7 +291,7 @@ impl Socket {
         target_os = "openbsd",
     ))]
     pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
-        let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?;
+        let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?;
         Ok(n as usize)
     }
 
@@ -319,7 +322,7 @@ impl Socket {
         target_os = "openbsd",
     ))]
     pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
-        let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?;
+        let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?;
         Ok(n as usize)
     }
 
@@ -369,7 +372,7 @@ impl Socket {
             Shutdown::Read => libc::SHUT_RD,
             Shutdown::Both => libc::SHUT_RDWR,
         };
-        cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
+        cvt(unsafe { libc::shutdown(self.as_raw_fd(), how) })?;
         Ok(())
     }
 
@@ -396,7 +399,7 @@ impl Socket {
     #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         let mut nonblocking = nonblocking as libc::c_int;
-        cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop)
+        cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop)
     }
 
     #[cfg(any(target_os = "solaris", target_os = "illumos"))]
@@ -410,23 +413,52 @@ impl Socket {
         let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
         if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
     }
+
+    // This is used by sys_common code to abstract over Windows and Unix.
+    pub fn as_raw(&self) -> RawFd {
+        self.as_raw_fd()
+    }
+}
+
+impl AsInner<FileDesc> for Socket {
+    fn as_inner(&self) -> &FileDesc {
+        &self.0
+    }
+}
+
+impl IntoInner<FileDesc> for Socket {
+    fn into_inner(self) -> FileDesc {
+        self.0
+    }
+}
+
+impl FromInner<FileDesc> for Socket {
+    fn from_inner(file_desc: FileDesc) -> Self {
+        Self(file_desc)
+    }
+}
+
+impl AsFd for Socket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
 }
 
-impl AsInner<c_int> for Socket {
-    fn as_inner(&self) -> &c_int {
-        self.0.as_inner()
+impl AsRawFd for Socket {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
     }
 }
 
-impl FromInner<c_int> for Socket {
-    fn from_inner(fd: c_int) -> Socket {
-        Socket(FileDesc::new(fd))
+impl IntoRawFd for Socket {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
     }
 }
 
-impl IntoInner<c_int> for Socket {
-    fn into_inner(self) -> c_int {
-        self.0.into_raw()
+impl FromRawFd for Socket {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FromRawFd::from_raw_fd(raw_fd))
     }
 }
 
diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs
index 7ae37bdda70..a56c275c942 100644
--- a/library/std/src/sys/unix/pipe.rs
+++ b/library/std/src/sys/unix/pipe.rs
@@ -1,7 +1,9 @@
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::mem;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::fd::FileDesc;
 use crate::sys::{cvt, cvt_r};
+use crate::sys_common::IntoInner;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Anonymous pipes
@@ -24,16 +26,20 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
             target_os = "openbsd",
             target_os = "redox"
         ))] {
-            cvt(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) })?;
-            Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
+            unsafe {
+                cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
+                Ok((AnonPipe(FileDesc::from_raw_fd(fds[0])), AnonPipe(FileDesc::from_raw_fd(fds[1]))))
+            }
         } else {
-            cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
-
-            let fd0 = FileDesc::new(fds[0]);
-            let fd1 = FileDesc::new(fds[1]);
-            fd0.set_cloexec()?;
-            fd1.set_cloexec()?;
-            Ok((AnonPipe(fd0), AnonPipe(fd1)))
+            unsafe {
+                cvt(libc::pipe(fds.as_mut_ptr()))?;
+
+                let fd0 = FileDesc::from_raw_fd(fds[0]);
+                let fd1 = FileDesc::from_raw_fd(fds[1]);
+                fd0.set_cloexec()?;
+                fd1.set_cloexec()?;
+                Ok((AnonPipe(fd0), AnonPipe(fd1)))
+            }
         }
     }
 }
@@ -64,11 +70,10 @@ impl AnonPipe {
     pub fn is_write_vectored(&self) -> bool {
         self.0.is_write_vectored()
     }
+}
 
-    pub fn fd(&self) -> &FileDesc {
-        &self.0
-    }
-    pub fn into_fd(self) -> FileDesc {
+impl IntoInner<FileDesc> for AnonPipe {
+    fn into_inner(self) -> FileDesc {
         self.0
     }
 }
@@ -76,15 +81,15 @@ impl AnonPipe {
 pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> {
     // Set both pipes into nonblocking mode as we're gonna be reading from both
     // in the `select` loop below, and we wouldn't want one to block the other!
-    let p1 = p1.into_fd();
-    let p2 = p2.into_fd();
+    let p1 = p1.into_inner();
+    let p2 = p2.into_inner();
     p1.set_nonblocking(true)?;
     p2.set_nonblocking(true)?;
 
     let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
-    fds[0].fd = p1.raw();
+    fds[0].fd = p1.as_raw_fd();
     fds[0].events = libc::POLLIN;
-    fds[1].fd = p2.raw();
+    fds[1].fd = p2.as_raw_fd();
     fds[1].events = libc::POLLIN;
     loop {
         // wait for either pipe to become readable using `poll`
@@ -120,3 +125,27 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) ->
         }
     }
 }
+
+impl AsRawFd for AnonPipe {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl AsFd for AnonPipe {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl IntoRawFd for AnonPipe {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for AnonPipe {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FromRawFd::from_raw_fd(raw_fd))
+    }
+}
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index a1972380a9f..7b261a302c3 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -13,6 +13,7 @@ use crate::sys::fd::FileDesc;
 use crate::sys::fs::File;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
+use crate::sys_common::IntoInner;
 
 #[cfg(not(target_os = "fuchsia"))]
 use crate::sys::fs::OpenOptions;
@@ -388,17 +389,17 @@ impl Stdio {
             // stderr. No matter which we dup first, the second will get
             // overwritten prematurely.
             Stdio::Fd(ref fd) => {
-                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
+                if fd.as_raw_fd() >= 0 && fd.as_raw_fd() <= libc::STDERR_FILENO {
                     Ok((ChildStdio::Owned(fd.duplicate()?), None))
                 } else {
-                    Ok((ChildStdio::Explicit(fd.raw()), None))
+                    Ok((ChildStdio::Explicit(fd.as_raw_fd()), None))
                 }
             }
 
             Stdio::MakePipe => {
                 let (reader, writer) = pipe::anon_pipe()?;
                 let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) };
-                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
+                Ok((ChildStdio::Owned(theirs.into_inner()), Some(ours)))
             }
 
             #[cfg(not(target_os = "fuchsia"))]
@@ -408,7 +409,7 @@ impl Stdio {
                 opts.write(!readable);
                 let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) };
                 let fd = File::open_c(&path, &opts)?;
-                Ok((ChildStdio::Owned(fd.into_fd()), None))
+                Ok((ChildStdio::Owned(fd.into_inner()), None))
             }
 
             #[cfg(target_os = "fuchsia")]
@@ -419,13 +420,13 @@ impl Stdio {
 
 impl From<AnonPipe> for Stdio {
     fn from(pipe: AnonPipe) -> Stdio {
-        Stdio::Fd(pipe.into_fd())
+        Stdio::Fd(pipe.into_inner())
     }
 }
 
 impl From<File> for Stdio {
     fn from(file: File) -> Stdio {
-        Stdio::Fd(file.into_fd())
+        Stdio::Fd(file.into_inner())
     }
 }
 
@@ -434,7 +435,7 @@ impl ChildStdio {
         match *self {
             ChildStdio::Inherit => None,
             ChildStdio::Explicit(fd) => Some(fd),
-            ChildStdio::Owned(ref fd) => Some(fd.raw()),
+            ChildStdio::Owned(ref fd) => Some(fd.as_raw_fd()),
 
             #[cfg(target_os = "fuchsia")]
             ChildStdio::Null => None,
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 4b210d6af13..12edf04a4e2 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -97,7 +97,9 @@ impl Command {
         drop(env_lock);
         drop(output);
 
-        let mut p = Process::new(pid, pidfd);
+        // Safety: We obtained the pidfd from calling `clone3` with
+        // `CLONE_PIDFD` so it's valid an otherwise unowned.
+        let mut p = unsafe { Process::new(pid, pidfd) };
         let mut bytes = [0; 8];
 
         // loop to handle EINTR
@@ -446,7 +448,8 @@ impl Command {
             None => None,
         };
 
-        let mut p = Process::new(0, -1);
+        // Safety: -1 indicates we don't have a pidfd.
+        let mut p = unsafe { Process::new(0, -1) };
 
         struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
 
@@ -545,14 +548,17 @@ pub struct Process {
 
 impl Process {
     #[cfg(target_os = "linux")]
-    fn new(pid: pid_t, pidfd: pid_t) -> Self {
+    unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self {
+        use crate::os::unix::io::FromRawFd;
         use crate::sys_common::FromInner;
-        let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::new(pidfd)));
+        // Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned.
+        let pidfd = (pidfd >= 0)
+            .then(|| PidFd::from_inner(unsafe { sys::fd::FileDesc::from_raw_fd(pidfd) }));
         Process { pid, status: None, pidfd }
     }
 
     #[cfg(not(target_os = "linux"))]
-    fn new(pid: pid_t, _pidfd: pid_t) -> Self {
+    unsafe fn new(pid: pid_t, _pidfd: pid_t) -> Self {
         Process { pid, status: None }
     }
 
diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs
index a05fe8165cf..b359987595d 100644
--- a/library/std/src/sys/unix/stdio.rs
+++ b/library/std/src/sys/unix/stdio.rs
@@ -1,5 +1,6 @@
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
+use crate::os::unix::io::{AsFd, BorrowedFd, FromRawFd};
 use crate::sys::fd::FileDesc;
 
 pub struct Stdin(());
@@ -14,11 +15,11 @@ impl Stdin {
 
 impl io::Read for Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read(buf)
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) }
     }
 
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs)
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) }
     }
 
     #[inline]
@@ -35,11 +36,13 @@ impl Stdout {
 
 impl io::Write for Stdout {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write(buf)
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write(buf) }
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs)
+        unsafe {
+            ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write_vectored(bufs)
+        }
     }
 
     #[inline]
@@ -60,11 +63,13 @@ impl Stderr {
 
 impl io::Write for Stderr {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write(buf)
+        unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write(buf) }
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs)
+        unsafe {
+            ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write_vectored(bufs)
+        }
     }
 
     #[inline]
@@ -86,3 +91,51 @@ pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
 pub fn panic_output() -> Option<impl io::Write> {
     Some(Stderr::new())
 }
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for io::Stdin {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<'a> AsFd for io::StdinLock<'a> {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for io::Stdout {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<'a> AsFd for io::StdoutLock<'a> {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl AsFd for io::Stderr {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) }
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<'a> AsFd for io::StderrLock<'a> {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) }
+    }
+}
diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs
index 1f6ea8d6e8d..e4f4456611c 100644
--- a/library/std/src/sys/wasi/fd.rs
+++ b/library/std/src/sys/wasi/fd.rs
@@ -5,11 +5,12 @@ use super::err2io;
 use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
 use crate::net::Shutdown;
-use crate::os::raw::c_int;
+use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 #[derive(Debug)]
 pub struct WasiFd {
-    fd: c_int,
+    fd: OwnedFd,
 }
 
 fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] {
@@ -27,38 +28,26 @@ fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] {
 }
 
 impl WasiFd {
-    pub unsafe fn from_raw(fd: c_int) -> WasiFd {
-        WasiFd { fd }
-    }
-
-    pub fn into_raw(self) -> c_int {
-        let ret = self.fd;
-        mem::forget(self);
-        ret
-    }
-
-    pub fn as_raw(&self) -> c_int {
-        self.fd
-    }
-
     pub fn datasync(&self) -> io::Result<()> {
-        unsafe { wasi::fd_datasync(self.fd as wasi::Fd).map_err(err2io) }
+        unsafe { wasi::fd_datasync(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
     }
 
     pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
-        unsafe { wasi::fd_pread(self.fd as wasi::Fd, iovec(bufs), offset).map_err(err2io) }
+        unsafe { wasi::fd_pread(self.as_raw_fd() as wasi::Fd, iovec(bufs), offset).map_err(err2io) }
     }
 
     pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
-        unsafe { wasi::fd_pwrite(self.fd as wasi::Fd, ciovec(bufs), offset).map_err(err2io) }
+        unsafe {
+            wasi::fd_pwrite(self.as_raw_fd() as wasi::Fd, ciovec(bufs), offset).map_err(err2io)
+        }
     }
 
     pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        unsafe { wasi::fd_read(self.fd as wasi::Fd, iovec(bufs)).map_err(err2io) }
+        unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) }
     }
 
     pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        unsafe { wasi::fd_write(self.fd as wasi::Fd, ciovec(bufs)).map_err(err2io) }
+        unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) }
     }
 
     pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
@@ -67,37 +56,42 @@ impl WasiFd {
             SeekFrom::End(pos) => (wasi::WHENCE_END, pos),
             SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos),
         };
-        unsafe { wasi::fd_seek(self.fd as wasi::Fd, offset, whence).map_err(err2io) }
+        unsafe { wasi::fd_seek(self.as_raw_fd() as wasi::Fd, offset, whence).map_err(err2io) }
     }
 
     pub fn tell(&self) -> io::Result<u64> {
-        unsafe { wasi::fd_tell(self.fd as wasi::Fd).map_err(err2io) }
+        unsafe { wasi::fd_tell(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
     }
 
     // FIXME: __wasi_fd_fdstat_get
 
     pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> {
-        unsafe { wasi::fd_fdstat_set_flags(self.fd as wasi::Fd, flags).map_err(err2io) }
+        unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
     }
 
     pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> {
-        unsafe { wasi::fd_fdstat_set_rights(self.fd as wasi::Fd, base, inheriting).map_err(err2io) }
+        unsafe {
+            wasi::fd_fdstat_set_rights(self.as_raw_fd() as wasi::Fd, base, inheriting)
+                .map_err(err2io)
+        }
     }
 
     pub fn sync(&self) -> io::Result<()> {
-        unsafe { wasi::fd_sync(self.fd as wasi::Fd).map_err(err2io) }
+        unsafe { wasi::fd_sync(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
     }
 
     pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> {
-        unsafe { wasi::fd_advise(self.fd as wasi::Fd, offset, len, advice).map_err(err2io) }
+        unsafe {
+            wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io)
+        }
     }
 
     pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
-        unsafe { wasi::fd_allocate(self.fd as wasi::Fd, offset, len).map_err(err2io) }
+        unsafe { wasi::fd_allocate(self.as_raw_fd() as wasi::Fd, offset, len).map_err(err2io) }
     }
 
     pub fn create_directory(&self, path: &str) -> io::Result<()> {
-        unsafe { wasi::path_create_directory(self.fd as wasi::Fd, path).map_err(err2io) }
+        unsafe { wasi::path_create_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
     }
 
     pub fn link(
@@ -109,10 +103,10 @@ impl WasiFd {
     ) -> io::Result<()> {
         unsafe {
             wasi::path_link(
-                self.fd as wasi::Fd,
+                self.as_raw_fd() as wasi::Fd,
                 old_flags,
                 old_path,
-                new_fd.fd as wasi::Fd,
+                new_fd.as_raw_fd() as wasi::Fd,
                 new_path,
             )
             .map_err(err2io)
@@ -130,7 +124,7 @@ impl WasiFd {
     ) -> io::Result<WasiFd> {
         unsafe {
             wasi::path_open(
-                self.fd as wasi::Fd,
+                self.as_raw_fd() as wasi::Fd,
                 dirflags,
                 path,
                 oflags,
@@ -138,34 +132,39 @@ impl WasiFd {
                 fs_rights_inheriting,
                 fs_flags,
             )
-            .map(|fd| WasiFd::from_raw(fd as c_int))
+            .map(|fd| WasiFd::from_raw_fd(fd as RawFd))
             .map_err(err2io)
         }
     }
 
     pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result<usize> {
         unsafe {
-            wasi::fd_readdir(self.fd as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie)
+            wasi::fd_readdir(self.as_raw_fd() as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie)
                 .map_err(err2io)
         }
     }
 
     pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result<usize> {
         unsafe {
-            wasi::path_readlink(self.fd as wasi::Fd, path, buf.as_mut_ptr(), buf.len())
+            wasi::path_readlink(self.as_raw_fd() as wasi::Fd, path, buf.as_mut_ptr(), buf.len())
                 .map_err(err2io)
         }
     }
 
     pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> {
         unsafe {
-            wasi::path_rename(self.fd as wasi::Fd, old_path, new_fd.fd as wasi::Fd, new_path)
-                .map_err(err2io)
+            wasi::path_rename(
+                self.as_raw_fd() as wasi::Fd,
+                old_path,
+                new_fd.as_raw_fd() as wasi::Fd,
+                new_path,
+            )
+            .map_err(err2io)
         }
     }
 
     pub fn filestat_get(&self) -> io::Result<wasi::Filestat> {
-        unsafe { wasi::fd_filestat_get(self.fd as wasi::Fd).map_err(err2io) }
+        unsafe { wasi::fd_filestat_get(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
     }
 
     pub fn filestat_set_times(
@@ -175,12 +174,13 @@ impl WasiFd {
         fstflags: wasi::Fstflags,
     ) -> io::Result<()> {
         unsafe {
-            wasi::fd_filestat_set_times(self.fd as wasi::Fd, atim, mtim, fstflags).map_err(err2io)
+            wasi::fd_filestat_set_times(self.as_raw_fd() as wasi::Fd, atim, mtim, fstflags)
+                .map_err(err2io)
         }
     }
 
     pub fn filestat_set_size(&self, size: u64) -> io::Result<()> {
-        unsafe { wasi::fd_filestat_set_size(self.fd as wasi::Fd, size).map_err(err2io) }
+        unsafe { wasi::fd_filestat_set_size(self.as_raw_fd() as wasi::Fd, size).map_err(err2io) }
     }
 
     pub fn path_filestat_get(
@@ -188,7 +188,9 @@ impl WasiFd {
         flags: wasi::Lookupflags,
         path: &str,
     ) -> io::Result<wasi::Filestat> {
-        unsafe { wasi::path_filestat_get(self.fd as wasi::Fd, flags, path).map_err(err2io) }
+        unsafe {
+            wasi::path_filestat_get(self.as_raw_fd() as wasi::Fd, flags, path).map_err(err2io)
+        }
     }
 
     pub fn path_filestat_set_times(
@@ -200,21 +202,30 @@ impl WasiFd {
         fstflags: wasi::Fstflags,
     ) -> io::Result<()> {
         unsafe {
-            wasi::path_filestat_set_times(self.fd as wasi::Fd, flags, path, atim, mtim, fstflags)
-                .map_err(err2io)
+            wasi::path_filestat_set_times(
+                self.as_raw_fd() as wasi::Fd,
+                flags,
+                path,
+                atim,
+                mtim,
+                fstflags,
+            )
+            .map_err(err2io)
         }
     }
 
     pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> {
-        unsafe { wasi::path_symlink(old_path, self.fd as wasi::Fd, new_path).map_err(err2io) }
+        unsafe {
+            wasi::path_symlink(old_path, self.as_raw_fd() as wasi::Fd, new_path).map_err(err2io)
+        }
     }
 
     pub fn unlink_file(&self, path: &str) -> io::Result<()> {
-        unsafe { wasi::path_unlink_file(self.fd as wasi::Fd, path).map_err(err2io) }
+        unsafe { wasi::path_unlink_file(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
     }
 
     pub fn remove_directory(&self, path: &str) -> io::Result<()> {
-        unsafe { wasi::path_remove_directory(self.fd as wasi::Fd, path).map_err(err2io) }
+        unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
     }
 
     pub fn sock_recv(
@@ -222,11 +233,15 @@ impl WasiFd {
         ri_data: &mut [IoSliceMut<'_>],
         ri_flags: wasi::Riflags,
     ) -> io::Result<(usize, wasi::Roflags)> {
-        unsafe { wasi::sock_recv(self.fd as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io) }
+        unsafe {
+            wasi::sock_recv(self.as_raw_fd() as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io)
+        }
     }
 
     pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result<usize> {
-        unsafe { wasi::sock_send(self.fd as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io) }
+        unsafe {
+            wasi::sock_send(self.as_raw_fd() as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io)
+        }
     }
 
     pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> {
@@ -235,14 +250,54 @@ impl WasiFd {
             Shutdown::Write => wasi::SDFLAGS_WR,
             Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD,
         };
-        unsafe { wasi::sock_shutdown(self.fd as wasi::Fd, how).map_err(err2io) }
+        unsafe { wasi::sock_shutdown(self.as_raw_fd() as wasi::Fd, how).map_err(err2io) }
+    }
+}
+
+impl AsInner<OwnedFd> for WasiFd {
+    fn as_inner(&self) -> &OwnedFd {
+        &self.fd
+    }
+}
+
+impl AsInnerMut<OwnedFd> for WasiFd {
+    fn as_inner_mut(&mut self) -> &mut OwnedFd {
+        &mut self.fd
+    }
+}
+
+impl IntoInner<OwnedFd> for WasiFd {
+    fn into_inner(self) -> OwnedFd {
+        self.fd
+    }
+}
+
+impl FromInner<OwnedFd> for WasiFd {
+    fn from_inner(owned_fd: OwnedFd) -> Self {
+        Self { fd: owned_fd }
+    }
+}
+
+impl AsFd for WasiFd {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.fd.as_fd()
+    }
+}
+
+impl AsRawFd for WasiFd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for WasiFd {
+    fn into_raw_fd(self) -> RawFd {
+        self.fd.into_raw_fd()
     }
 }
 
-impl Drop for WasiFd {
-    fn drop(&mut self) {
-        // FIXME: can we handle the return code here even though we can't on
-        // unix?
-        let _ = unsafe { wasi::fd_close(self.fd as wasi::Fd) };
+impl FromRawFd for WasiFd {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
     }
 }
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 55c9c652a8b..984dda8dc0b 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -8,12 +8,13 @@ use crate::iter;
 use crate::mem::{self, ManuallyDrop};
 use crate::os::raw::c_int;
 use crate::os::wasi::ffi::{OsStrExt, OsStringExt};
+use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sync::Arc;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
-use crate::sys_common::FromInner;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 pub use crate::sys_common::fs::{remove_dir_all, try_exists};
 
@@ -442,22 +443,50 @@ impl File {
         unsupported()
     }
 
-    pub fn fd(&self) -> &WasiFd {
+    pub fn read_link(&self, file: &Path) -> io::Result<PathBuf> {
+        read_link(&self.fd, file)
+    }
+}
+
+impl AsInner<WasiFd> for File {
+    fn as_inner(&self) -> &WasiFd {
         &self.fd
     }
+}
 
-    pub fn into_fd(self) -> WasiFd {
+impl IntoInner<WasiFd> for File {
+    fn into_inner(self) -> WasiFd {
         self.fd
     }
+}
 
-    pub fn read_link(&self, file: &Path) -> io::Result<PathBuf> {
-        read_link(&self.fd, file)
+impl FromInner<WasiFd> for File {
+    fn from_inner(fd: WasiFd) -> File {
+        File { fd }
+    }
+}
+
+impl AsFd for File {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.fd.as_fd()
+    }
+}
+
+impl AsRawFd for File {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for File {
+    fn into_raw_fd(self) -> RawFd {
+        self.fd.into_raw_fd()
     }
 }
 
-impl FromInner<c_int> for File {
-    fn from_inner(fd: c_int) -> File {
-        unsafe { File { fd: WasiFd::from_raw(fd) } }
+impl FromRawFd for File {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
     }
 }
 
@@ -474,7 +503,7 @@ impl DirBuilder {
 
 impl fmt::Debug for File {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("File").field("fd", &self.fd.as_raw()).finish()
+        f.debug_struct("File").field("fd", &self.as_raw_fd()).finish()
     }
 }
 
@@ -654,7 +683,7 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
             let relative = CStr::from_ptr(relative_path).to_bytes().to_vec();
 
             return Ok((
-                ManuallyDrop::new(WasiFd::from_raw(fd as c_int)),
+                ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)),
                 PathBuf::from(OsString::from_vec(relative)),
             ));
         }
diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs
index 50b7352933e..c7c4a9f6efd 100644
--- a/library/std/src/sys/wasi/net.rs
+++ b/library/std/src/sys/wasi/net.rs
@@ -5,13 +5,57 @@ use crate::convert::TryFrom;
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::os::raw::c_int;
+use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::unsupported;
-use crate::sys_common::FromInner;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
+pub struct Socket(WasiFd);
+
 pub struct TcpStream {
-    fd: WasiFd,
+    inner: Socket,
+}
+
+impl AsInner<WasiFd> for Socket {
+    fn as_inner(&self) -> &WasiFd {
+        &self.0
+    }
+}
+
+impl IntoInner<WasiFd> for Socket {
+    fn into_inner(self) -> WasiFd {
+        self.0
+    }
+}
+
+impl FromInner<WasiFd> for Socket {
+    fn from_inner(inner: WasiFd) -> Socket {
+        Socket(inner)
+    }
+}
+
+impl AsFd for Socket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for Socket {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for Socket {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for Socket {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
+    }
 }
 
 impl TcpStream {
@@ -107,29 +151,29 @@ impl TcpStream {
         unsupported()
     }
 
-    pub fn fd(&self) -> &WasiFd {
-        &self.fd
+    pub fn socket(&self) -> &Socket {
+        &self.inner
     }
 
-    pub fn into_fd(self) -> WasiFd {
-        self.fd
+    pub fn into_socket(self) -> Socket {
+        self.inner
     }
 }
 
-impl FromInner<c_int> for TcpStream {
-    fn from_inner(fd: c_int) -> TcpStream {
-        unsafe { TcpStream { fd: WasiFd::from_raw(fd) } }
+impl FromInner<Socket> for TcpStream {
+    fn from_inner(socket: Socket) -> TcpStream {
+        TcpStream { inner: socket }
     }
 }
 
 impl fmt::Debug for TcpStream {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("TcpStream").field("fd", &self.fd.as_raw()).finish()
+        f.debug_struct("TcpStream").field("fd", &self.inner.as_raw_fd()).finish()
     }
 }
 
 pub struct TcpListener {
-    fd: WasiFd,
+    inner: Socket,
 }
 
 impl TcpListener {
@@ -173,29 +217,41 @@ impl TcpListener {
         unsupported()
     }
 
-    pub fn fd(&self) -> &WasiFd {
-        &self.fd
+    pub fn socket(&self) -> &Socket {
+        &self.inner
     }
 
-    pub fn into_fd(self) -> WasiFd {
-        self.fd
+    pub fn into_socket(self) -> Socket {
+        self.inner
     }
 }
 
-impl FromInner<c_int> for TcpListener {
-    fn from_inner(fd: c_int) -> TcpListener {
-        unsafe { TcpListener { fd: WasiFd::from_raw(fd) } }
+impl AsInner<Socket> for TcpListener {
+    fn as_inner(&self) -> &Socket {
+        &self.inner
+    }
+}
+
+impl IntoInner<Socket> for TcpListener {
+    fn into_inner(self) -> Socket {
+        self.inner
+    }
+}
+
+impl FromInner<Socket> for TcpListener {
+    fn from_inner(inner: Socket) -> TcpListener {
+        TcpListener { inner }
     }
 }
 
 impl fmt::Debug for TcpListener {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("TcpListener").field("fd", &self.fd.as_raw()).finish()
+        f.debug_struct("TcpListener").field("fd", &self.inner.as_raw_fd()).finish()
     }
 }
 
 pub struct UdpSocket {
-    fd: WasiFd,
+    inner: Socket,
 }
 
 impl UdpSocket {
@@ -323,24 +379,36 @@ impl UdpSocket {
         unsupported()
     }
 
-    pub fn fd(&self) -> &WasiFd {
-        &self.fd
+    pub fn socket(&self) -> &Socket {
+        &self.inner
+    }
+
+    pub fn into_socket(self) -> Socket {
+        self.inner
     }
+}
+
+impl AsInner<Socket> for UdpSocket {
+    fn as_inner(&self) -> &Socket {
+        &self.inner
+    }
+}
 
-    pub fn into_fd(self) -> WasiFd {
-        self.fd
+impl IntoInner<Socket> for UdpSocket {
+    fn into_inner(self) -> Socket {
+        self.inner
     }
 }
 
-impl FromInner<c_int> for UdpSocket {
-    fn from_inner(fd: c_int) -> UdpSocket {
-        unsafe { UdpSocket { fd: WasiFd::from_raw(fd) } }
+impl FromInner<Socket> for UdpSocket {
+    fn from_inner(inner: Socket) -> UdpSocket {
+        UdpSocket { inner }
     }
 }
 
 impl fmt::Debug for UdpSocket {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("UdpSocket").field("fd", &self.fd.as_raw()).finish()
+        f.debug_struct("UdpSocket").field("fd", &self.inner.as_raw_fd()).finish()
     }
 }
 
diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs
index 8782f333a1f..2c8f394cd47 100644
--- a/library/std/src/sys/wasi/stdio.rs
+++ b/library/std/src/sys/wasi/stdio.rs
@@ -4,6 +4,7 @@ use super::fd::WasiFd;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
 use crate::os::raw;
+use crate::os::wasi::io::{AsRawFd, FromRawFd};
 
 pub struct Stdin;
 pub struct Stdout;
@@ -13,9 +14,11 @@ impl Stdin {
     pub const fn new() -> Stdin {
         Stdin
     }
+}
 
+impl AsRawFd for Stdin {
     #[inline]
-    pub fn as_raw_fd(&self) -> raw::c_int {
+    fn as_raw_fd(&self) -> raw::c_int {
         0
     }
 }
@@ -26,7 +29,7 @@ impl io::Read for Stdin {
     }
 
     fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data)
+        ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).read(data)
     }
 
     #[inline]
@@ -39,9 +42,11 @@ impl Stdout {
     pub const fn new() -> Stdout {
         Stdout
     }
+}
 
+impl AsRawFd for Stdout {
     #[inline]
-    pub fn as_raw_fd(&self) -> raw::c_int {
+    fn as_raw_fd(&self) -> raw::c_int {
         1
     }
 }
@@ -52,7 +57,7 @@ impl io::Write for Stdout {
     }
 
     fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
+        ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data)
     }
 
     #[inline]
@@ -68,9 +73,11 @@ impl Stderr {
     pub const fn new() -> Stderr {
         Stderr
     }
+}
 
+impl AsRawFd for Stderr {
     #[inline]
-    pub fn as_raw_fd(&self) -> raw::c_int {
+    fn as_raw_fd(&self) -> raw::c_int {
         2
     }
 }
@@ -81,7 +88,7 @@ impl io::Write for Stderr {
     }
 
     fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
+        ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data)
     }
 
     #[inline]
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index c677adae688..0c1a50e231c 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -4,6 +4,7 @@ use crate::ffi::OsString;
 use crate::fmt;
 use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
+use crate::os::windows::io::{AsHandle, BorrowedHandle};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::slice;
@@ -11,7 +12,7 @@ use crate::sync::Arc;
 use crate::sys::handle::Handle;
 use crate::sys::time::SystemTime;
 use crate::sys::{c, cvt};
-use crate::sys_common::FromInner;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 use super::to_u16s;
 
@@ -295,12 +296,12 @@ impl File {
         if handle == c::INVALID_HANDLE_VALUE {
             Err(Error::last_os_error())
         } else {
-            Ok(File { handle: Handle::new(handle) })
+            unsafe { Ok(File { handle: Handle::from_raw_handle(handle) }) }
         }
     }
 
     pub fn fsync(&self) -> io::Result<()> {
-        cvt(unsafe { c::FlushFileBuffers(self.handle.raw()) })?;
+        cvt(unsafe { c::FlushFileBuffers(self.handle.as_raw_handle()) })?;
         Ok(())
     }
 
@@ -313,7 +314,7 @@ impl File {
         let size = mem::size_of_val(&info);
         cvt(unsafe {
             c::SetFileInformationByHandle(
-                self.handle.raw(),
+                self.handle.as_raw_handle(),
                 c::FileEndOfFileInfo,
                 &mut info as *mut _ as *mut _,
                 size as c::DWORD,
@@ -326,7 +327,7 @@ impl File {
     pub fn file_attr(&self) -> io::Result<FileAttr> {
         unsafe {
             let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed();
-            cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))?;
+            cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
             let mut reparse_tag = 0;
             if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
                 let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
@@ -449,7 +450,7 @@ impl File {
         };
         let pos = pos as c::LARGE_INTEGER;
         let mut newpos = 0;
-        cvt(unsafe { c::SetFilePointerEx(self.handle.raw(), pos, &mut newpos, whence) })?;
+        cvt(unsafe { c::SetFilePointerEx(self.handle.as_raw_handle(), pos, &mut newpos, whence) })?;
         Ok(newpos as u64)
     }
 
@@ -457,14 +458,6 @@ impl File {
         Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? })
     }
 
-    pub fn handle(&self) -> &Handle {
-        &self.handle
-    }
-
-    pub fn into_handle(self) -> Handle {
-        self.handle
-    }
-
     fn reparse_point<'a>(
         &self,
         space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE],
@@ -473,7 +466,7 @@ impl File {
             let mut bytes = 0;
             cvt({
                 c::DeviceIoControl(
-                    self.handle.raw(),
+                    self.handle.as_raw_handle(),
                     c::FSCTL_GET_REPARSE_POINT,
                     ptr::null_mut(),
                     0,
@@ -541,7 +534,7 @@ impl File {
         let size = mem::size_of_val(&info);
         cvt(unsafe {
             c::SetFileInformationByHandle(
-                self.handle.raw(),
+                self.handle.as_raw_handle(),
                 c::FileBasicInfo,
                 &mut info as *mut _ as *mut _,
                 size as c::DWORD,
@@ -551,9 +544,45 @@ impl File {
     }
 }
 
-impl FromInner<c::HANDLE> for File {
-    fn from_inner(handle: c::HANDLE) -> File {
-        File { handle: Handle::new(handle) }
+impl AsInner<Handle> for File {
+    fn as_inner(&self) -> &Handle {
+        &self.handle
+    }
+}
+
+impl IntoInner<Handle> for File {
+    fn into_inner(self) -> Handle {
+        self.handle
+    }
+}
+
+impl FromInner<Handle> for File {
+    fn from_inner(handle: Handle) -> File {
+        File { handle: handle }
+    }
+}
+
+impl AsHandle for File {
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        self.as_inner().as_handle()
+    }
+}
+
+impl AsRawHandle for File {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().as_raw_handle()
+    }
+}
+
+impl IntoRawHandle for File {
+    fn into_raw_handle(self) -> RawHandle {
+        self.into_inner().into_raw_handle()
+    }
+}
+
+impl FromRawHandle for File {
+    unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
+        Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) }
     }
 }
 
@@ -561,7 +590,7 @@ impl fmt::Debug for File {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // FIXME(#24570): add more info here (e.g., mode)
         let mut b = f.debug_struct("File");
-        b.field("handle", &self.handle.raw());
+        b.field("handle", &self.handle.as_raw_handle());
         if let Ok(path) = get_path(&self) {
             b.field("path", &path);
         }
@@ -838,7 +867,7 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
 fn get_path(f: &File) -> io::Result<PathBuf> {
     super::fill_utf16_buf(
         |buf, sz| unsafe {
-            c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, c::VOLUME_NAME_DOS)
+            c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS)
         },
         |buf| PathBuf::from(OsString::from_wide(buf)),
     )
@@ -909,7 +938,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
     opts.write(true);
     opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
     let f = File::open(junction, &opts)?;
-    let h = f.handle().raw();
+    let h = f.as_inner().as_raw_handle();
 
     unsafe {
         let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index 0d4baa3b340..21d86b00226 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -3,76 +3,87 @@
 use crate::cmp;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read};
 use crate::mem;
-use crate::ops::Deref;
+use crate::os::windows::io::{
+    AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
+};
 use crate::ptr;
 use crate::sys::c;
 use crate::sys::cvt;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 /// An owned container for `HANDLE` object, closing them on Drop.
 ///
 /// All methods are inherited through a `Deref` impl to `RawHandle`
-pub struct Handle(RawHandle);
-
-/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference
-/// as well as Rust-y methods.
-///
-/// This does **not** drop the handle when it goes out of scope, use `Handle`
-/// instead for that.
-#[derive(Copy, Clone)]
-pub struct RawHandle(c::HANDLE);
-
-unsafe impl Send for RawHandle {}
-unsafe impl Sync for RawHandle {}
+pub struct Handle(OwnedHandle);
 
 impl Handle {
-    pub fn new(handle: c::HANDLE) -> Handle {
-        Handle(RawHandle::new(handle))
-    }
-
     pub fn new_event(manual: bool, init: bool) -> io::Result<Handle> {
         unsafe {
             let event =
                 c::CreateEventW(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null());
-            if event.is_null() { Err(io::Error::last_os_error()) } else { Ok(Handle::new(event)) }
+            if event.is_null() {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(Handle::from_raw_handle(event))
+            }
         }
     }
+}
 
-    pub fn into_raw(self) -> c::HANDLE {
-        let ret = self.raw();
-        mem::forget(self);
-        ret
+impl AsInner<OwnedHandle> for Handle {
+    fn as_inner(&self) -> &OwnedHandle {
+        &self.0
     }
 }
 
-impl Deref for Handle {
-    type Target = RawHandle;
-    fn deref(&self) -> &RawHandle {
-        &self.0
+impl IntoInner<OwnedHandle> for Handle {
+    fn into_inner(self) -> OwnedHandle {
+        self.0
     }
 }
 
-impl Drop for Handle {
-    fn drop(&mut self) {
-        unsafe {
-            let _ = c::CloseHandle(self.raw());
-        }
+impl FromInner<OwnedHandle> for Handle {
+    fn from_inner(file_desc: OwnedHandle) -> Self {
+        Self(file_desc)
     }
 }
 
-impl RawHandle {
-    pub fn new(handle: c::HANDLE) -> RawHandle {
-        RawHandle(handle)
+impl AsHandle for Handle {
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        self.0.as_handle()
     }
+}
 
-    pub fn raw(&self) -> c::HANDLE {
-        self.0
+impl AsRawHandle for Handle {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.0.as_raw_handle()
     }
+}
 
+impl IntoRawHandle for Handle {
+    fn into_raw_handle(self) -> RawHandle {
+        self.0.into_raw_handle()
+    }
+}
+
+impl FromRawHandle for Handle {
+    unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
+        Self(FromRawHandle::from_raw_handle(raw_handle))
+    }
+}
+
+impl Handle {
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let mut read = 0;
         let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         let res = cvt(unsafe {
-            c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, ptr::null_mut())
+            c::ReadFile(
+                self.as_raw_handle(),
+                buf.as_mut_ptr() as c::LPVOID,
+                len,
+                &mut read,
+                ptr::null_mut(),
+            )
         });
 
         match res {
@@ -104,7 +115,13 @@ impl RawHandle {
             let mut overlapped: c::OVERLAPPED = mem::zeroed();
             overlapped.Offset = offset as u32;
             overlapped.OffsetHigh = (offset >> 32) as u32;
-            cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, &mut overlapped))
+            cvt(c::ReadFile(
+                self.as_raw_handle(),
+                buf.as_mut_ptr() as c::LPVOID,
+                len,
+                &mut read,
+                &mut overlapped,
+            ))
         };
         match res {
             Ok(_) => Ok(read as usize),
@@ -120,7 +137,13 @@ impl RawHandle {
     ) -> io::Result<Option<usize>> {
         let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         let mut amt = 0;
-        let res = cvt(c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped));
+        let res = cvt(c::ReadFile(
+            self.as_raw_handle(),
+            buf.as_ptr() as c::LPVOID,
+            len,
+            &mut amt,
+            overlapped,
+        ));
         match res {
             Ok(_) => Ok(Some(amt as usize)),
             Err(e) => {
@@ -143,7 +166,8 @@ impl RawHandle {
         unsafe {
             let mut bytes = 0;
             let wait = if wait { c::TRUE } else { c::FALSE };
-            let res = cvt(c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait));
+            let res =
+                cvt(c::GetOverlappedResult(self.as_raw_handle(), overlapped, &mut bytes, wait));
             match res {
                 Ok(_) => Ok(bytes as usize),
                 Err(e) => {
@@ -160,14 +184,20 @@ impl RawHandle {
     }
 
     pub fn cancel_io(&self) -> io::Result<()> {
-        unsafe { cvt(c::CancelIo(self.raw())).map(drop) }
+        unsafe { cvt(c::CancelIo(self.as_raw_handle())).map(drop) }
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let mut amt = 0;
         let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         cvt(unsafe {
-            c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, ptr::null_mut())
+            c::WriteFile(
+                self.as_raw_handle(),
+                buf.as_ptr() as c::LPVOID,
+                len,
+                &mut amt,
+                ptr::null_mut(),
+            )
         })?;
         Ok(amt as usize)
     }
@@ -189,7 +219,7 @@ impl RawHandle {
             overlapped.Offset = offset as u32;
             overlapped.OffsetHigh = (offset >> 32) as u32;
             cvt(c::WriteFile(
-                self.0,
+                self.as_raw_handle(),
                 buf.as_ptr() as c::LPVOID,
                 len,
                 &mut written,
@@ -210,7 +240,7 @@ impl RawHandle {
             let cur_proc = c::GetCurrentProcess();
             c::DuplicateHandle(
                 cur_proc,
-                self.0,
+                self.as_raw_handle(),
                 cur_proc,
                 &mut ret,
                 access,
@@ -218,11 +248,11 @@ impl RawHandle {
                 options,
             )
         })?;
-        Ok(Handle::new(ret))
+        unsafe { Ok(Handle::from_raw_handle(ret)) }
     }
 }
 
-impl<'a> Read for &'a RawHandle {
+impl<'a> Read for &'a Handle {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 9cea5c5e63a..55aacb38c6f 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -4,6 +4,9 @@ use crate::cmp;
 use crate::io::{self, IoSlice, IoSliceMut, Read};
 use crate::mem;
 use crate::net::{Shutdown, SocketAddr};
+use crate::os::windows::io::{
+    AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
+};
 use crate::ptr;
 use crate::sync::Once;
 use crate::sys;
@@ -24,7 +27,7 @@ pub mod netc {
     pub use crate::sys::c::*;
 }
 
-pub struct Socket(c::SOCKET);
+pub struct Socket(OwnedSocket);
 
 static INIT: Once = Once::new();
 
@@ -109,7 +112,7 @@ impl Socket {
         };
 
         if socket != c::INVALID_SOCKET {
-            Ok(Self(socket))
+            unsafe { Ok(Self::from_raw_socket(socket)) }
         } else {
             let error = unsafe { c::WSAGetLastError() };
 
@@ -124,9 +127,11 @@ impl Socket {
                 return Err(last_error());
             }
 
-            let socket = Self(socket);
-            socket.set_no_inherit()?;
-            Ok(socket)
+            unsafe {
+                let socket = Self::from_raw_socket(socket);
+                socket.set_no_inherit()?;
+                Ok(socket)
+            }
         }
     }
 
@@ -134,7 +139,7 @@ impl Socket {
         self.set_nonblocking(true)?;
         let result = {
             let (addrp, len) = addr.into_inner();
-            let result = unsafe { c::connect(self.0, addrp, len) };
+            let result = unsafe { c::connect(self.as_raw_socket(), addrp, len) };
             cvt(result).map(drop)
         };
         self.set_nonblocking(false)?;
@@ -160,7 +165,7 @@ impl Socket {
                 let fds = {
                     let mut fds = unsafe { mem::zeroed::<c::fd_set>() };
                     fds.fd_count = 1;
-                    fds.fd_array[0] = self.0;
+                    fds.fd_array[0] = self.as_raw_socket();
                     fds
                 };
 
@@ -194,17 +199,19 @@ impl Socket {
     }
 
     pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> {
-        let socket = unsafe { c::accept(self.0, storage, len) };
+        let socket = unsafe { c::accept(self.as_raw_socket(), storage, len) };
 
         match socket {
             c::INVALID_SOCKET => Err(last_error()),
-            _ => Ok(Self(socket)),
+            _ => unsafe { Ok(Self::from_raw_socket(socket)) },
         }
     }
 
     pub fn duplicate(&self) -> io::Result<Socket> {
         let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
-        let result = unsafe { c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info) };
+        let result = unsafe {
+            c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
+        };
         cvt(result)?;
         let socket = unsafe {
             c::WSASocketW(
@@ -218,7 +225,7 @@ impl Socket {
         };
 
         if socket != c::INVALID_SOCKET {
-            Ok(Self(socket))
+            unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) }
         } else {
             let error = unsafe { c::WSAGetLastError() };
 
@@ -241,9 +248,11 @@ impl Socket {
                 return Err(last_error());
             }
 
-            let socket = Self(socket);
-            socket.set_no_inherit()?;
-            Ok(socket)
+            unsafe {
+                let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket));
+                socket.set_no_inherit()?;
+                Ok(socket)
+            }
         }
     }
 
@@ -251,7 +260,8 @@ impl Socket {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
         let length = cmp::min(buf.len(), i32::MAX as usize) as i32;
-        let result = unsafe { c::recv(self.0, buf.as_mut_ptr() as *mut _, length, flags) };
+        let result =
+            unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) };
 
         match result {
             c::SOCKET_ERROR => {
@@ -279,7 +289,7 @@ impl Socket {
         let mut flags = 0;
         let result = unsafe {
             c::WSARecv(
-                self.0,
+                self.as_raw_socket(),
                 bufs.as_mut_ptr() as *mut c::WSABUF,
                 length,
                 &mut nread,
@@ -325,7 +335,7 @@ impl Socket {
         // do the same on windows to map a shut down socket to returning EOF.
         let result = unsafe {
             c::recvfrom(
-                self.0,
+                self.as_raw_socket(),
                 buf.as_mut_ptr() as *mut _,
                 length,
                 flags,
@@ -361,7 +371,7 @@ impl Socket {
         let mut nwritten = 0;
         let result = unsafe {
             c::WSASend(
-                self.0,
+                self.as_raw_socket(),
                 bufs.as_ptr() as *const c::WSABUF as *mut _,
                 length,
                 &mut nwritten,
@@ -408,8 +418,10 @@ impl Socket {
 
     #[cfg(not(target_vendor = "uwp"))]
     fn set_no_inherit(&self) -> io::Result<()> {
-        sys::cvt(unsafe { c::SetHandleInformation(self.0 as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) })
-            .map(drop)
+        sys::cvt(unsafe {
+            c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
+        })
+        .map(drop)
     }
 
     #[cfg(target_vendor = "uwp")]
@@ -423,13 +435,14 @@ impl Socket {
             Shutdown::Read => c::SD_RECEIVE,
             Shutdown::Both => c::SD_BOTH,
         };
-        let result = unsafe { c::shutdown(self.0, how) };
+        let result = unsafe { c::shutdown(self.as_raw_socket(), how) };
         cvt(result).map(drop)
     }
 
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         let mut nonblocking = nonblocking as c_ulong;
-        let result = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
+        let result =
+            unsafe { c::ioctlsocket(self.as_raw_socket(), c::FIONBIO as c_int, &mut nonblocking) };
         cvt(result).map(drop)
     }
 
@@ -446,6 +459,11 @@ impl Socket {
         let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?;
         if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
     }
+
+    // This is used by sys_common code to abstract over Windows and Unix.
+    pub fn as_raw(&self) -> RawSocket {
+        self.as_inner().as_raw_socket()
+    }
 }
 
 #[unstable(reason = "not public", issue = "none", feature = "fd_read")]
@@ -455,28 +473,44 @@ impl<'a> Read for &'a Socket {
     }
 }
 
-impl Drop for Socket {
-    fn drop(&mut self) {
-        let _ = unsafe { c::closesocket(self.0) };
+impl AsInner<OwnedSocket> for Socket {
+    fn as_inner(&self) -> &OwnedSocket {
+        &self.0
     }
 }
 
-impl AsInner<c::SOCKET> for Socket {
-    fn as_inner(&self) -> &c::SOCKET {
-        &self.0
+impl FromInner<OwnedSocket> for Socket {
+    fn from_inner(sock: OwnedSocket) -> Socket {
+        Socket(sock)
     }
 }
 
-impl FromInner<c::SOCKET> for Socket {
-    fn from_inner(sock: c::SOCKET) -> Socket {
-        Socket(sock)
+impl IntoInner<OwnedSocket> for Socket {
+    fn into_inner(self) -> OwnedSocket {
+        self.0
+    }
+}
+
+impl AsSocket for Socket {
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        self.0.as_socket()
+    }
+}
+
+impl AsRawSocket for Socket {
+    fn as_raw_socket(&self) -> RawSocket {
+        self.0.as_raw_socket()
+    }
+}
+
+impl IntoRawSocket for Socket {
+    fn into_raw_socket(self) -> RawSocket {
+        self.0.into_raw_socket()
     }
 }
 
-impl IntoInner<c::SOCKET> for Socket {
-    fn into_inner(self) -> c::SOCKET {
-        let ret = self.0;
-        mem::forget(self);
-        ret
+impl FromRawSocket for Socket {
+    unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self {
+        Self(FromRawSocket::from_raw_socket(raw_socket))
     }
 }
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index 8db97ba50a8..883690c4831 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -288,7 +288,7 @@ fn home_dir_crt() -> Option<PathBuf> {
         if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
             return None;
         }
-        let _handle = Handle::new(token);
+        let _handle = Handle::from_raw_handle(token);
         super::fill_utf16_buf(
             |buf, mut sz| {
                 match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs
index 104a8db4659..63d3d6c5ed4 100644
--- a/library/std/src/sys/windows/pipe.rs
+++ b/library/std/src/sys/windows/pipe.rs
@@ -12,6 +12,7 @@ use crate::sys::c;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
 use crate::sys::hashmap_random_keys;
+use crate::sys_common::IntoInner;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Anonymous pipes
@@ -21,6 +22,12 @@ pub struct AnonPipe {
     inner: Handle,
 }
 
+impl IntoInner<Handle> for AnonPipe {
+    fn into_inner(self) -> Handle {
+        self.inner
+    }
+}
+
 pub struct Pipes {
     pub ours: AnonPipe,
     pub theirs: AnonPipe,
@@ -123,7 +130,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
                 }
                 return Err(err);
             }
-            ours = Handle::new(handle);
+            ours = Handle::from_raw_handle(handle);
             break;
         }
 
@@ -146,11 +153,11 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
         };
         opts.security_attributes(&mut sa);
         let theirs = File::open(Path::new(&name), &opts)?;
-        let theirs = AnonPipe { inner: theirs.into_handle() };
+        let theirs = AnonPipe { inner: theirs.into_inner() };
 
         Ok(Pipes {
             ours: AnonPipe { inner: ours },
-            theirs: AnonPipe { inner: theirs.into_handle() },
+            theirs: AnonPipe { inner: theirs.into_inner() },
         })
     }
 }
@@ -207,7 +214,7 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) ->
 
     let mut p1 = AsyncPipe::new(p1, v1)?;
     let mut p2 = AsyncPipe::new(p2, v2)?;
-    let objs = [p1.event.raw(), p2.event.raw()];
+    let objs = [p1.event.as_raw_handle(), p2.event.as_raw_handle()];
 
     // In a loop we wait for either pipe's scheduled read operation to complete.
     // If the operation completes with 0 bytes, that means EOF was reached, in
@@ -262,7 +269,7 @@ impl<'a> AsyncPipe<'a> {
         // I/O operation is successfully scheduled (what we want).
         let event = Handle::new_event(true, true)?;
         let mut overlapped: Box<c::OVERLAPPED> = unsafe { Box::new(mem::zeroed()) };
-        overlapped.hEvent = event.raw();
+        overlapped.hEvent = event.as_raw_handle();
         Ok(AsyncPipe { pipe, overlapped, event, dst, state: State::NotReading })
     }
 
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index ae193b82e91..ccff90629a3 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -15,6 +15,7 @@ use crate::io::{self, Error, ErrorKind};
 use crate::mem;
 use crate::num::NonZeroI32;
 use crate::os::windows::ffi::OsStrExt;
+use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
 use crate::path::Path;
 use crate::ptr;
 use crate::sys::c;
@@ -26,7 +27,7 @@ use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::stdio;
 use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::sys_common::AsInner;
+use crate::sys_common::{AsInner, IntoInner};
 
 use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
 
@@ -316,9 +317,9 @@ impl Command {
         let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?;
         let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?;
         let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?;
-        si.hStdInput = stdin.raw();
-        si.hStdOutput = stdout.raw();
-        si.hStdError = stderr.raw();
+        si.hStdInput = stdin.as_raw_handle();
+        si.hStdOutput = stdout.as_raw_handle();
+        si.hStdError = stderr.as_raw_handle();
 
         unsafe {
             cvt(c::CreateProcessW(
@@ -338,9 +339,11 @@ impl Command {
         // We close the thread handle because we don't care about keeping
         // the thread id valid, and we aren't keeping the thread handle
         // around to be able to close it later.
-        drop(Handle::new(pi.hThread));
+        unsafe {
+            drop(Handle::from_raw_handle(pi.hThread));
 
-        Ok((Process { handle: Handle::new(pi.hProcess) }, pipes))
+            Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes))
+        }
     }
 }
 
@@ -365,13 +368,13 @@ impl Stdio {
             // should still be unavailable so propagate the
             // INVALID_HANDLE_VALUE.
             Stdio::Inherit => match stdio::get_handle(stdio_id) {
-                Ok(io) => {
-                    let io = Handle::new(io);
+                Ok(io) => unsafe {
+                    let io = Handle::from_raw_handle(io);
                     let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
-                    io.into_raw();
+                    io.into_raw_handle();
                     ret
-                }
-                Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
+                },
+                Err(..) => unsafe { Ok(Handle::from_raw_handle(c::INVALID_HANDLE_VALUE)) },
             },
 
             Stdio::MakePipe => {
@@ -397,7 +400,7 @@ impl Stdio {
                 opts.read(stdio_id == c::STD_INPUT_HANDLE);
                 opts.write(stdio_id != c::STD_INPUT_HANDLE);
                 opts.security_attributes(&mut sa);
-                File::open(Path::new("NUL"), &opts).map(|file| file.into_handle())
+                File::open(Path::new("NUL"), &opts).map(|file| file.into_inner())
             }
         }
     }
@@ -411,7 +414,7 @@ impl From<AnonPipe> for Stdio {
 
 impl From<File> for Stdio {
     fn from(file: File) -> Stdio {
-        Stdio::Handle(file.into_handle())
+        Stdio::Handle(file.into_inner())
     }
 }
 
@@ -430,29 +433,29 @@ pub struct Process {
 
 impl Process {
     pub fn kill(&mut self) -> io::Result<()> {
-        cvt(unsafe { c::TerminateProcess(self.handle.raw(), 1) })?;
+        cvt(unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) })?;
         Ok(())
     }
 
     pub fn id(&self) -> u32 {
-        unsafe { c::GetProcessId(self.handle.raw()) as u32 }
+        unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 }
     }
 
     pub fn wait(&mut self) -> io::Result<ExitStatus> {
         unsafe {
-            let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE);
+            let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE);
             if res != c::WAIT_OBJECT_0 {
                 return Err(Error::last_os_error());
             }
             let mut status = 0;
-            cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
+            cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?;
             Ok(ExitStatus(status))
         }
     }
 
     pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         unsafe {
-            match c::WaitForSingleObject(self.handle.raw(), 0) {
+            match c::WaitForSingleObject(self.handle.as_raw_handle(), 0) {
                 c::WAIT_OBJECT_0 => {}
                 c::WAIT_TIMEOUT => {
                     return Ok(None);
@@ -460,7 +463,7 @@ impl Process {
                 _ => return Err(io::Error::last_os_error()),
             }
             let mut status = 0;
-            cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
+            cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?;
             Ok(Some(ExitStatus(status)))
         }
     }
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 2973951fe90..1cf0e9f0cf1 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -3,6 +3,7 @@
 use crate::char::decode_utf16;
 use crate::cmp;
 use crate::io;
+use crate::os::windows::io::{FromRawHandle, IntoRawHandle};
 use crate::ptr;
 use crate::str;
 use crate::sys::c;
@@ -53,10 +54,12 @@ fn is_console(handle: c::HANDLE) -> bool {
 fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> {
     let handle = get_handle(handle_id)?;
     if !is_console(handle) {
-        let handle = Handle::new(handle);
-        let ret = handle.write(data);
-        handle.into_raw(); // Don't close the handle
-        return ret;
+        unsafe {
+            let handle = Handle::from_raw_handle(handle);
+            let ret = handle.write(data);
+            handle.into_raw_handle(); // Don't close the handle
+            return ret;
+        }
     }
 
     // As the console is meant for presenting text, we assume bytes of `data` come from a string
@@ -140,10 +143,12 @@ impl io::Read for Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         let handle = get_handle(c::STD_INPUT_HANDLE)?;
         if !is_console(handle) {
-            let handle = Handle::new(handle);
-            let ret = handle.read(buf);
-            handle.into_raw(); // Don't close the handle
-            return ret;
+            unsafe {
+                let handle = Handle::from_raw_handle(handle);
+                let ret = handle.read(buf);
+                handle.into_raw_handle(); // Don't close the handle
+                return ret;
+            }
         }
 
         if buf.len() == 0 {
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index ef7a9733fd8..a5293133b3a 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -1,6 +1,7 @@
 use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZeroUsize;
+use crate::os::windows::io::{AsRawHandle, FromRawHandle};
 use crate::ptr;
 use crate::sys::c;
 use crate::sys::handle::Handle;
@@ -45,7 +46,7 @@ impl Thread {
             drop(Box::from_raw(p));
             Err(io::Error::last_os_error())
         } else {
-            Ok(Thread { handle: Handle::new(ret) })
+            Ok(Thread { handle: Handle::from_raw_handle(ret) })
         };
 
         extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
@@ -71,7 +72,7 @@ impl Thread {
     }
 
     pub fn join(self) {
-        let rc = unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE) };
+        let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
         if rc == c::WAIT_FAILED {
             panic!("failed to join on thread: {}", io::Error::last_os_error());
         }
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index d5f29c4a439..0ffa5c01dd3 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -61,13 +61,7 @@ cfg_if::cfg_if! {
 pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> {
     unsafe {
         let payload = &payload as *const T as *const c_void;
-        cvt(c::setsockopt(
-            *sock.as_inner(),
-            opt,
-            val,
-            payload,
-            mem::size_of::<T>() as c::socklen_t,
-        ))?;
+        cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::<T>() as c::socklen_t))?;
         Ok(())
     }
 }
@@ -76,7 +70,7 @@ pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<
     unsafe {
         let mut slot: T = mem::zeroed();
         let mut len = mem::size_of::<T>() as c::socklen_t;
-        cvt(c::getsockopt(*sock.as_inner(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?;
+        cvt(c::getsockopt(sock.as_raw(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?;
         assert_eq!(len as usize, mem::size_of::<T>());
         Ok(slot)
     }
@@ -217,7 +211,7 @@ impl TcpStream {
         let sock = Socket::new(addr, c::SOCK_STREAM)?;
 
         let (addrp, len) = addr.into_inner();
-        cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?;
+        cvt_r(|| unsafe { c::connect(sock.as_raw(), addrp, len) })?;
         Ok(TcpStream { inner: sock })
     }
 
@@ -273,7 +267,7 @@ impl TcpStream {
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
         let ret = cvt(unsafe {
-            c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
+            c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
         })?;
         Ok(ret as usize)
     }
@@ -288,11 +282,11 @@ impl TcpStream {
     }
 
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) })
+        sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) })
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) })
+        sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) })
     }
 
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
@@ -348,7 +342,7 @@ impl fmt::Debug for TcpStream {
         }
 
         let name = if cfg!(windows) { "socket" } else { "fd" };
-        res.field(name, &self.inner.as_inner()).finish()
+        res.field(name, &self.inner.as_raw()).finish()
     }
 }
 
@@ -380,10 +374,10 @@ impl TcpListener {
 
         // Bind our new socket
         let (addrp, len) = addr.into_inner();
-        cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
+        cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?;
 
         // Start listening
-        cvt(unsafe { c::listen(*sock.as_inner(), 128) })?;
+        cvt(unsafe { c::listen(sock.as_raw(), 128) })?;
         Ok(TcpListener { inner: sock })
     }
 
@@ -396,7 +390,7 @@ impl TcpListener {
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) })
+        sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) })
     }
 
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
@@ -453,7 +447,7 @@ impl fmt::Debug for TcpListener {
         }
 
         let name = if cfg!(windows) { "socket" } else { "fd" };
-        res.field(name, &self.inner.as_inner()).finish()
+        res.field(name, &self.inner.as_raw()).finish()
     }
 }
 
@@ -473,7 +467,7 @@ impl UdpSocket {
 
         let sock = Socket::new(addr, c::SOCK_DGRAM)?;
         let (addrp, len) = addr.into_inner();
-        cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
+        cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?;
         Ok(UdpSocket { inner: sock })
     }
 
@@ -486,11 +480,11 @@ impl UdpSocket {
     }
 
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) })
+        sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) })
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) })
+        sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) })
     }
 
     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
@@ -506,7 +500,7 @@ impl UdpSocket {
         let (dstp, dstlen) = dst.into_inner();
         let ret = cvt(unsafe {
             c::sendto(
-                *self.inner.as_inner(),
+                self.inner.as_raw(),
                 buf.as_ptr() as *const c_void,
                 len,
                 MSG_NOSIGNAL,
@@ -643,14 +637,14 @@ impl UdpSocket {
     pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
         let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
         let ret = cvt(unsafe {
-            c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
+            c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
         })?;
         Ok(ret as usize)
     }
 
     pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
         let (addrp, len) = addr?.into_inner();
-        cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(drop)
+        cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addrp, len) }).map(drop)
     }
 }
 
@@ -669,6 +663,6 @@ impl fmt::Debug for UdpSocket {
         }
 
         let name = if cfg!(windows) { "socket" } else { "fd" };
-        res.field(name, &self.inner.as_inner()).finish()
+        res.field(name, &self.inner.as_raw()).finish()
     }
 }
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 6d70c7270d3..ec105f231e5 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -12,15 +12,14 @@
 
 #![stable(feature = "time", since = "1.3.0")]
 
+mod monotonic;
 #[cfg(test)]
 mod tests;
 
-use crate::cmp;
 use crate::error::Error;
 use crate::fmt;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::sys::time;
-use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::FromInner;
 
 #[stable(feature = "time", since = "1.3.0")]
@@ -249,14 +248,7 @@ impl Instant {
             return Instant(os_now);
         }
 
-        static LOCK: StaticMutex = StaticMutex::new();
-        static mut LAST_NOW: time::Instant = time::Instant::zero();
-        unsafe {
-            let _lock = LOCK.lock();
-            let now = cmp::max(LAST_NOW, os_now);
-            LAST_NOW = now;
-            Instant(now)
-        }
+        Instant(monotonic::monotonize(os_now))
     }
 
     /// Returns the amount of time elapsed from another instant to this one.
diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
new file mode 100644
index 00000000000..27fee6acff3
--- /dev/null
+++ b/library/std/src/time/monotonic.rs
@@ -0,0 +1,115 @@
+use crate::sys::time;
+
+#[inline]
+pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
+    inner::monotonize(raw)
+}
+
+#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
+pub mod inner {
+    use crate::sync::atomic::AtomicU64;
+    use crate::sync::atomic::Ordering::*;
+    use crate::sys::time;
+    use crate::time::Duration;
+
+    pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();
+
+    // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
+    const UNINITIALIZED: u64 = 0b11 << 30;
+    static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);
+
+    #[inline]
+    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
+        monotonize_impl(&MONO, raw)
+    }
+
+    #[inline]
+    pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
+        let delta = raw.checked_sub_instant(&ZERO).unwrap();
+        let secs = delta.as_secs();
+        // occupies no more than 30 bits (10^9 seconds)
+        let nanos = delta.subsec_nanos() as u64;
+
+        // This wraps around every 136 years (2^32 seconds).
+        // To detect backsliding we use wrapping arithmetic and declare forward steps smaller
+        // than 2^31 seconds as expected and everything else as a backslide which will be
+        // monotonized.
+        // This could be a problem for programs that call instants at intervals greater
+        // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
+        let packed = (secs << 32) | nanos;
+        let old = mono.load(Relaxed);
+
+        if old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2 {
+            mono.store(packed, Relaxed);
+            raw
+        } else {
+            // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
+            // passed in value and the 64bits loaded from the atomic
+            let seconds_lower = old >> 32;
+            let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
+            if secs & 0xffff_ffff > seconds_lower {
+                // Backslide caused the lower 32bit of the seconds part to wrap.
+                // This must be the case because the seconds part is larger even though
+                // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
+                //
+                // We assume that backslides are smaller than 2^32 seconds
+                // which means we need to add 1 to the upper half to restore it.
+                //
+                // Example:
+                // most recent observed time: 0xA1_0000_0000_0000_0000u128
+                // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
+                // backslide by 1s
+                // caller time is             0xA0_ffff_ffff_0000_0000u128
+                // -> we can fix up the upper half time by adding 1 << 32
+                seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
+            }
+            let secs = seconds_upper | seconds_lower;
+            let nanos = old as u32;
+            ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
+        }
+    }
+}
+
+#[cfg(target_has_atomic = "128")]
+pub mod inner {
+    use crate::sync::atomic::AtomicU128;
+    use crate::sync::atomic::Ordering::*;
+    use crate::sys::time;
+    use crate::time::Duration;
+
+    const ZERO: time::Instant = time::Instant::zero();
+    static MONO: AtomicU128 = AtomicU128::new(0);
+
+    #[inline]
+    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
+        let delta = raw.checked_sub_instant(&ZERO).unwrap();
+        // Split into seconds and nanos since Duration doesn't have a
+        // constructor that takes an u128
+        let secs = delta.as_secs() as u128;
+        let nanos = delta.subsec_nanos() as u128;
+        let timestamp: u128 = secs << 64 | nanos;
+        let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
+        let secs = (timestamp >> 64) as u64;
+        let nanos = timestamp as u32;
+        ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
+    }
+}
+
+#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
+pub mod inner {
+    use crate::cmp;
+    use crate::sys::time;
+    use crate::sys_common::mutex::StaticMutex;
+
+    #[inline]
+    pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
+        static LOCK: StaticMutex = StaticMutex::new();
+        static mut LAST_NOW: time::Instant = time::Instant::zero();
+        unsafe {
+            let _lock = LOCK.lock();
+            let now = cmp::max(LAST_NOW, os_now);
+            LAST_NOW = now;
+            now
+        }
+    }
+}
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index 20c813fdc70..dc44c9346b6 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -1,4 +1,6 @@
 use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
+#[cfg(not(target_arch = "wasm32"))]
+use test::{black_box, Bencher};
 
 macro_rules! assert_almost_eq {
     ($a:expr, $b:expr) => {{
@@ -13,8 +15,34 @@ macro_rules! assert_almost_eq {
 #[test]
 fn instant_monotonic() {
     let a = Instant::now();
-    let b = Instant::now();
-    assert!(b >= a);
+    loop {
+        let b = Instant::now();
+        assert!(b >= a);
+        if b > a {
+            break;
+        }
+    }
+}
+
+#[test]
+#[cfg(not(target_arch = "wasm32"))]
+fn instant_monotonic_concurrent() -> crate::thread::Result<()> {
+    let threads: Vec<_> = (0..8)
+        .map(|_| {
+            crate::thread::spawn(|| {
+                let mut old = Instant::now();
+                for _ in 0..5_000_000 {
+                    let new = Instant::now();
+                    assert!(new >= old);
+                    old = new;
+                }
+            })
+        })
+        .collect();
+    for t in threads {
+        t.join()?;
+    }
+    Ok(())
 }
 
 #[test]
@@ -163,3 +191,71 @@ fn since_epoch() {
     let hundred_twenty_years = thirty_years * 4;
     assert!(a < hundred_twenty_years);
 }
+
+#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
+#[test]
+fn monotonizer_wrapping_backslide() {
+    use super::monotonic::inner::{monotonize_impl, ZERO};
+    use core::sync::atomic::AtomicU64;
+
+    let reference = AtomicU64::new(0);
+
+    let time = match ZERO.checked_add_duration(&Duration::from_secs(0xffff_ffff)) {
+        Some(time) => time,
+        None => {
+            // platform cannot represent u32::MAX seconds so it won't have to deal with this kind
+            // of overflow either
+            return;
+        }
+    };
+
+    let monotonized = monotonize_impl(&reference, time);
+    let expected = ZERO.checked_add_duration(&Duration::from_secs(1 << 32)).unwrap();
+    assert_eq!(
+        monotonized, expected,
+        "64bit monotonizer should handle overflows in the seconds part"
+    );
+}
+
+macro_rules! bench_instant_threaded {
+    ($bench_name:ident, $thread_count:expr) => {
+        #[bench]
+        #[cfg(not(target_arch = "wasm32"))]
+        fn $bench_name(b: &mut Bencher) -> crate::thread::Result<()> {
+            use crate::sync::atomic::{AtomicBool, Ordering};
+            use crate::sync::Arc;
+
+            let running = Arc::new(AtomicBool::new(true));
+
+            let threads: Vec<_> = (0..$thread_count)
+                .map(|_| {
+                    let flag = Arc::clone(&running);
+                    crate::thread::spawn(move || {
+                        while flag.load(Ordering::Relaxed) {
+                            black_box(Instant::now());
+                        }
+                    })
+                })
+                .collect();
+
+            b.iter(|| {
+                let a = Instant::now();
+                let b = Instant::now();
+                assert!(b >= a);
+            });
+
+            running.store(false, Ordering::Relaxed);
+
+            for t in threads {
+                t.join()?;
+            }
+            Ok(())
+        }
+    };
+}
+
+bench_instant_threaded!(instant_contention_01_threads, 0);
+bench_instant_threaded!(instant_contention_02_threads, 1);
+bench_instant_threaded!(instant_contention_04_threads, 3);
+bench_instant_threaded!(instant_contention_08_threads, 7);
+bench_instant_threaded!(instant_contention_16_threads, 15);
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index e2f34826111..5911309a044 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1288,7 +1288,7 @@ impl<'a> Builder<'a> {
         // requirement, but the `-L` library path is not propagated across
         // separate Cargo projects. We can add LLVM's library path to the
         // platform-specific environment variable as a workaround.
-        if mode == Mode::ToolRustc {
+        if mode == Mode::ToolRustc || mode == Mode::Codegen {
             if let Some(llvm_config) = self.llvm_config(target) {
                 let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
                 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 78c9a252622..d2598995478 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -806,6 +806,10 @@ impl Step for CodegenBackend {
 
         let tmp_stamp = out_dir.join(".tmp.stamp");
 
+        builder.info(&format!(
+            "Building stage{} codegen backend {} ({} -> {})",
+            compiler.stage, backend, &compiler.host, target
+        ));
         let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false);
         if builder.config.dry_run {
             return;
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index b32629af4d3..d1397394be7 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -180,6 +180,7 @@ impl Step for Llvm {
             .define("LLVM_INCLUDE_EXAMPLES", "OFF")
             .define("LLVM_INCLUDE_DOCS", "OFF")
             .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
+            .define("LLVM_INCLUDE_TESTS", "OFF")
             .define("LLVM_ENABLE_TERMINFO", "OFF")
             .define("LLVM_ENABLE_LIBEDIT", "OFF")
             .define("LLVM_ENABLE_BINDINGS", "OFF")
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index a28762ac485..74e50c60610 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -166,11 +166,6 @@ pub fn check(build: &mut Build) {
     }
 
     for target in &build.targets {
-        // Can't compile for iOS unless we're on macOS
-        if target.contains("apple-ios") && !build.build.contains("apple-darwin") {
-            panic!("the iOS target is only supported on macOS");
-        }
-
         build
             .config
             .target_config
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 59a1d06dabd..6417f5a984a 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -206,6 +206,10 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/verify-line-endings.sh
         <<: *step
 
+      - name: ensure backported commits are in upstream branches
+        run: src/ci/scripts/verify-backported-commits.sh
+        <<: *step
+
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
diff --git a/src/ci/scripts/verify-backported-commits.sh b/src/ci/scripts/verify-backported-commits.sh
new file mode 100755
index 00000000000..1023e4b0e28
--- /dev/null
+++ b/src/ci/scripts/verify-backported-commits.sh
@@ -0,0 +1,150 @@
+#!/bin/bash
+# Ensure commits in beta are in master & commits in stable are in beta + master.
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+
+# We don't care about commits that predate this automation check, so we pass a
+# `<limit>` argument to `git cherry`.
+BETA_LIMIT="53fd98ca776cb875bc9e5514f56b52eb74f9e7a9"
+STABLE_LIMIT="a178d0322ce20e33eac124758e837cbd80a6f633"
+
+verify_backported_commits_main() {
+  ci_base_branch=$(ciBaseBranch)
+
+  if [[ "$ci_base_branch" != "beta" && "$ci_base_branch" != "stable" ]]; then
+    echo 'Skipping. This is only run when merging to the beta or stable branches.'
+    exit 0
+  fi
+
+  echo 'git: unshallowing the repository so we can check commits'
+  git fetch \
+    --no-tags \
+    --no-recurse-submodules \
+    --progress \
+    --prune \
+    --unshallow
+
+  if [[ $ci_base_branch == "beta" ]]; then
+    verify_cherries master "$BETA_LIMIT" \
+      || exit 1
+
+  elif [[ $ci_base_branch == "stable" ]]; then
+    (verify_cherries master "$STABLE_LIMIT" \
+      & verify_cherries beta "$STABLE_LIMIT") \
+      || exit 1
+
+  fi
+}
+
+# Verify all commits in `HEAD` are backports of a commit in <upstream>. See
+# https://git-scm.com/docs/git-cherry for an explanation of the arguments.
+#
+# $1 = <upstream>
+# $2 = <limit>
+verify_cherries() {
+  # commits that lack a `backport-of` comment.
+  local no_backports=()
+  # commits with an incorrect `backport-of` comment.
+  local bad_backports=()
+
+  commits=$(git cherry "origin/$1" HEAD "$2")
+
+  if [[ -z "$commits" ]]; then
+    echo "All commits in \`HEAD\` are present in \`$1\`"
+    return 0
+  fi
+
+  commits=$(echo "$commits" | grep '^\+' | cut -c 3-)
+
+  while read sha; do
+    # Check each commit in <current>..<upstream>
+    backport_sha=$(get_backport "$sha")
+
+    if [[ "$backport_sha" == "nothing" ]]; then
+      echo "✓ \`$sha\` backports nothing"
+      continue
+    fi
+
+    if [[ -z "$backport_sha" ]]; then
+      no_backports+=("$sha")
+      continue
+    fi
+
+    if ! is_in_master "$backport_sha"; then
+      bad_backports+=("$sha")
+      continue
+    fi
+
+    echo "✓ \`$sha\` backports \`$backport_sha\`"
+  done <<< "$commits"
+
+  failure=0
+
+  if [ ${#no_backports[@]} -ne 0 ]; then
+        echo 'Error: Could not find backports for all commits.'
+        echo
+        echo 'All commits in \`HEAD\` are required to have a corresponding upstream commit.'
+        echo 'It looks like the following commits:'
+        echo
+        for commit in "${no_backports[@]}"; do
+          echo "    $commit"
+        done
+        echo
+        echo "do not match any commits in \`$1\`. If this was intended, add the text"
+        echo '\`backport-of: <SHA of a commit already in master>\`'
+        echo 'somewhere in the message of each of these commits.'
+        echo
+        failure=1
+  fi
+
+  if [ ${#bad_backports[@]} -ne 0 ]; then
+        echo 'Error: Found incorrectly marked commits.'
+        echo
+        echo 'The following commits:'
+        echo
+        for commit in "${bad_backports[@]}"; do
+          echo "    $commit"
+        done
+        echo
+        echo 'have commit messages marked \`backport-of: <SHA>\`, but the SHA is not in'
+        echo '\`master\`.'
+        echo
+        failure=1
+  fi
+
+  return $failure
+}
+
+# Get the backport of a commit. It echoes one of:
+#
+# 1. A SHA of the backported commit
+# 2. The string "nothing"
+# 3. An empty string
+#
+# $1 = <sha>
+get_backport() {
+  # This regex is:
+  #
+  # ^.* - throw away any extra starting characters
+  # backport-of: - prefix
+  # \s\? - optional space
+  # \(\) - capture group
+  # [a-f0-9]\+\|nothing - a SHA or the text 'nothing'
+  # .* - throw away any extra ending characters
+  # \1 - replace it with the first match
+  # {s//\1/p;q} - print the first occurrence and quit
+  #
+  git show -s --format=%B "$1" \
+    | sed -n '/^.*backport-of:\s\?\([a-f0-9]\+\|nothing\).*/{s//\1/p;q}'
+}
+
+# Check if a commit is in master.
+#
+# $1 = <sha>
+is_in_master() {
+  git merge-base --is-ancestor "$1" origin/master 2> /dev/null
+}
+
+verify_backported_commits_main
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 73b5ef0857d..b6ff3890c58 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -332,6 +332,7 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
             ty::PredicateKind::ConstEvaluatable(..) => None,
 
             ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::WellFormed(..)
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 782ff8df17b..70255749143 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -168,6 +168,7 @@ impl ExternalCrate {
     crate fn location(
         &self,
         extern_url: Option<&str>,
+        extern_url_takes_precedence: bool,
         dst: &std::path::Path,
         tcx: TyCtxt<'_>,
     ) -> ExternalLocation {
@@ -189,8 +190,10 @@ impl ExternalCrate {
             return Local;
         }
 
-        if let Some(url) = extern_url {
-            return to_remote(url);
+        if extern_url_takes_precedence {
+            if let Some(url) = extern_url {
+                return to_remote(url);
+            }
         }
 
         // Failing that, see if there's an attribute specifying where to find this
@@ -202,6 +205,7 @@ impl ExternalCrate {
             .filter_map(|a| a.value_str())
             .map(to_remote)
             .next()
+            .or(extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
             .unwrap_or(Unknown) // Well, at least we tried.
     }
 
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index e44158bc042..eef6985ea30 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -233,6 +233,8 @@ crate struct RenderOptions {
     crate extension_css: Option<PathBuf>,
     /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`.
     crate extern_html_root_urls: BTreeMap<String, String>,
+    /// Whether to give precedence to `html_root_url` or `--exten-html-root-url`.
+    crate extern_html_root_takes_precedence: bool,
     /// A map of the default settings (values are as for DOM storage API). Keys should lack the
     /// `rustdoc-` prefix.
     crate default_settings: FxHashMap<String, String>,
@@ -658,6 +660,8 @@ impl Options {
         let show_type_layout = matches.opt_present("show-type-layout");
         let nocapture = matches.opt_present("nocapture");
         let generate_link_to_definition = matches.opt_present("generate-link-to-definition");
+        let extern_html_root_takes_precedence =
+            matches.opt_present("extern-html-root-takes-precedence");
 
         if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) {
             diag.struct_err(
@@ -714,6 +718,7 @@ impl Options {
                 themes,
                 extension_css,
                 extern_html_root_urls,
+                extern_html_root_takes_precedence,
                 default_settings,
                 resource_suffix,
                 enable_minification,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 512c4ed2d3c..e96eba2f17d 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -528,9 +528,7 @@ crate fn run_global_ctxt(
 
     let render_options = ctxt.render_options;
     let mut cache = ctxt.cache;
-    krate = tcx.sess.time("create_format_cache", || {
-        cache.populate(krate, tcx, &render_options.extern_html_root_urls, &render_options.output)
-    });
+    krate = tcx.sess.time("create_format_cache", || cache.populate(krate, tcx, &render_options));
 
     // The main crate doc comments are always collapsed.
     krate.collapsed = true;
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 3d267ca5033..d45f277a0a8 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,6 +1,4 @@
-use std::collections::BTreeMap;
 use std::mem;
-use std::path::Path;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
@@ -9,6 +7,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
 use crate::clean::{self, GetDefId, ItemId};
+use crate::config::RenderOptions;
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
@@ -142,19 +141,21 @@ impl Cache {
         &mut self,
         mut krate: clean::Crate,
         tcx: TyCtxt<'_>,
-        extern_html_root_urls: &BTreeMap<String, String>,
-        dst: &Path,
+        render_options: &RenderOptions,
     ) -> clean::Crate {
         // Crawl the crate to build various caches used for the output
         debug!(?self.crate_version);
         self.traits = krate.external_traits.take();
+        let RenderOptions { extern_html_root_takes_precedence, output: dst, .. } = render_options;
 
         // Cache where all our extern crates are located
         // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
         for &e in &krate.externs {
             let name = e.name(tcx);
-            let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u);
-            self.extern_locations.insert(e.crate_num, e.location(extern_url, &dst, tcx));
+            let extern_url =
+                render_options.extern_html_root_urls.get(&*name.as_str()).map(|u| &**u);
+            let location = e.location(extern_url, *extern_html_root_takes_precedence, dst, tcx);
+            self.extern_locations.insert(e.crate_num, location);
             self.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module));
         }
 
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 3cdb1352bef..f8fc9243e14 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -65,10 +65,11 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
         out.push_buffer(extra);
     }
     if let Some(class) = class {
-        writeln!(out, "<pre class=\"rust {}\">", class);
+        write!(out, "<pre class=\"rust {}\">", class);
     } else {
-        writeln!(out, "<pre class=\"rust\">");
+        write!(out, "<pre class=\"rust\">");
     }
+    write!(out, "<code>");
 }
 
 /// Convert the given `src` source code into HTML by adding classes for highlighting.
@@ -101,7 +102,7 @@ fn write_code(
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
-    writeln!(out, "</pre>{}</div>", playground_button.unwrap_or_default());
+    writeln!(out, "</code></pre>{}</div>", playground_button.unwrap_or_default());
 }
 
 /// How a span of text is classified. Mostly corresponds to token kinds.
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 472323daf30..7c6d7dff816 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -234,7 +234,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
                     return Some(Event::Html(
                         format!(
                             "<div class=\"example-wrap\">\
-                                 <pre class=\"language-{}\">{}</pre>\
+                                 <pre class=\"language-{}\"><code>{}</code></pre>\
                              </div>",
                             lang,
                             Escape(&text),
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index a3b01a59f27..96cc67ce97c 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -454,24 +454,25 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         + name.as_str().len()
         + generics_len;
 
-    w.write_str("<pre class=\"rust fn\">");
-    render_attributes_in_pre(w, it, "");
-    w.reserve(header_len);
-    write!(
-        w,
-        "{vis}{constness}{asyncness}{unsafety}{abi}fn \
-         {name}{generics}{decl}{notable_traits}{where_clause}</pre>",
-        vis = vis,
-        constness = constness,
-        asyncness = asyncness,
-        unsafety = unsafety,
-        abi = abi,
-        name = name,
-        generics = f.generics.print(cx),
-        where_clause = print_where_clause(&f.generics, cx, 0, true),
-        decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
-        notable_traits = notable_traits_decl(&f.decl, cx),
-    );
+    wrap_item(w, "fn", |w| {
+        render_attributes_in_pre(w, it, "");
+        w.reserve(header_len);
+        write!(
+            w,
+            "{vis}{constness}{asyncness}{unsafety}{abi}fn \
+             {name}{generics}{decl}{notable_traits}{where_clause}",
+            vis = vis,
+            constness = constness,
+            asyncness = asyncness,
+            unsafety = unsafety,
+            abi = abi,
+            name = name,
+            generics = f.generics.print(cx),
+            where_clause = print_where_clause(&f.generics, cx, 0, true),
+            decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
+            notable_traits = notable_traits_decl(&f.decl, cx),
+        );
+    });
     document(w, cx, it, None)
 }
 
@@ -487,108 +488,111 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
 
     // Output the trait definition
     wrap_into_docblock(w, |w| {
-        w.write_str("<pre class=\"rust trait\">");
-        render_attributes_in_pre(w, it, "");
-        write!(
-            w,
-            "{}{}{}trait {}{}{}",
-            it.visibility.print_with_space(it.def_id, cx),
-            t.unsafety.print_with_space(),
-            if t.is_auto { "auto " } else { "" },
-            it.name.as_ref().unwrap(),
-            t.generics.print(cx),
-            bounds
-        );
-
-        if !t.generics.where_predicates.is_empty() {
-            write!(w, "{}", print_where_clause(&t.generics, cx, 0, true));
-        } else {
-            w.write_str(" ");
-        }
+        wrap_item(w, "trait", |w| {
+            render_attributes_in_pre(w, it, "");
+            write!(
+                w,
+                "{}{}{}trait {}{}{}",
+                it.visibility.print_with_space(it.def_id, cx),
+                t.unsafety.print_with_space(),
+                if t.is_auto { "auto " } else { "" },
+                it.name.as_ref().unwrap(),
+                t.generics.print(cx),
+                bounds
+            );
 
-        if t.items.is_empty() {
-            w.write_str("{ }");
-        } else {
-            // FIXME: we should be using a derived_id for the Anchors here
-            w.write_str("{\n");
-            let mut toggle = false;
-
-            // If there are too many associated types, hide _everything_
-            if should_hide_fields(count_types) {
-                toggle = true;
-                toggle_open(
-                    w,
-                    format_args!("{} associated items", count_types + count_consts + count_methods),
-                );
-            }
-            for t in &types {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
-                w.write_str(";\n");
-            }
-            // If there are too many associated constants, hide everything after them
-            // We also do this if the types + consts is large because otherwise we could
-            // render a bunch of types and _then_ a bunch of consts just because both were
-            // _just_ under the limit
-            if !toggle && should_hide_fields(count_types + count_consts) {
-                toggle = true;
-                toggle_open(
-                    w,
-                    format_args!(
-                        "{} associated constant{} and {} method{}",
-                        count_consts,
-                        pluralize(count_consts),
-                        count_methods,
-                        pluralize(count_methods),
-                    ),
-                );
-            }
-            if !types.is_empty() && !consts.is_empty() {
-                w.write_str("\n");
-            }
-            for t in &consts {
-                render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
-                w.write_str(";\n");
-            }
-            if !toggle && should_hide_fields(count_methods) {
-                toggle = true;
-                toggle_open(w, format_args!("{} methods", count_methods));
-            }
-            if !consts.is_empty() && !required.is_empty() {
-                w.write_str("\n");
+            if !t.generics.where_predicates.is_empty() {
+                write!(w, "{}", print_where_clause(&t.generics, cx, 0, true));
+            } else {
+                w.write_str(" ");
             }
-            for (pos, m) in required.iter().enumerate() {
-                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
-                w.write_str(";\n");
 
-                if pos < required.len() - 1 {
-                    w.write_str("<div class=\"item-spacer\"></div>");
+            if t.items.is_empty() {
+                w.write_str("{ }");
+            } else {
+                // FIXME: we should be using a derived_id for the Anchors here
+                w.write_str("{\n");
+                let mut toggle = false;
+
+                // If there are too many associated types, hide _everything_
+                if should_hide_fields(count_types) {
+                    toggle = true;
+                    toggle_open(
+                        w,
+                        format_args!(
+                            "{} associated items",
+                            count_types + count_consts + count_methods
+                        ),
+                    );
                 }
-            }
-            if !required.is_empty() && !provided.is_empty() {
-                w.write_str("\n");
-            }
-            for (pos, m) in provided.iter().enumerate() {
-                render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
-                match *m.kind {
-                    clean::MethodItem(ref inner, _)
-                        if !inner.generics.where_predicates.is_empty() =>
-                    {
-                        w.write_str(",\n    { ... }\n");
+                for t in &types {
+                    render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+                    w.write_str(";\n");
+                }
+                // If there are too many associated constants, hide everything after them
+                // We also do this if the types + consts is large because otherwise we could
+                // render a bunch of types and _then_ a bunch of consts just because both were
+                // _just_ under the limit
+                if !toggle && should_hide_fields(count_types + count_consts) {
+                    toggle = true;
+                    toggle_open(
+                        w,
+                        format_args!(
+                            "{} associated constant{} and {} method{}",
+                            count_consts,
+                            pluralize(count_consts),
+                            count_methods,
+                            pluralize(count_methods),
+                        ),
+                    );
+                }
+                if !types.is_empty() && !consts.is_empty() {
+                    w.write_str("\n");
+                }
+                for t in &consts {
+                    render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+                    w.write_str(";\n");
+                }
+                if !toggle && should_hide_fields(count_methods) {
+                    toggle = true;
+                    toggle_open(w, format_args!("{} methods", count_methods));
+                }
+                if !consts.is_empty() && !required.is_empty() {
+                    w.write_str("\n");
+                }
+                for (pos, m) in required.iter().enumerate() {
+                    render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+                    w.write_str(";\n");
+
+                    if pos < required.len() - 1 {
+                        w.write_str("<div class=\"item-spacer\"></div>");
                     }
-                    _ => {
-                        w.write_str(" { ... }\n");
+                }
+                if !required.is_empty() && !provided.is_empty() {
+                    w.write_str("\n");
+                }
+                for (pos, m) in provided.iter().enumerate() {
+                    render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+                    match *m.kind {
+                        clean::MethodItem(ref inner, _)
+                            if !inner.generics.where_predicates.is_empty() =>
+                        {
+                            w.write_str(",\n    { ... }\n");
+                        }
+                        _ => {
+                            w.write_str(" { ... }\n");
+                        }
+                    }
+                    if pos < provided.len() - 1 {
+                        w.write_str("<div class=\"item-spacer\"></div>");
                     }
                 }
-                if pos < provided.len() - 1 {
-                    w.write_str("<div class=\"item-spacer\"></div>");
+                if toggle {
+                    toggle_close(w);
                 }
+                w.write_str("}");
             }
-            if toggle {
-                toggle_close(w);
-            }
-            w.write_str("}");
-        }
-        w.write_str("</pre>")
+        });
     });
 
     // Trait documentation
@@ -811,16 +815,17 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
 }
 
 fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
-    w.write_str("<pre class=\"rust trait-alias\">");
-    render_attributes_in_pre(w, it, "");
-    write!(
-        w,
-        "trait {}{}{} = {};</pre>",
-        it.name.as_ref().unwrap(),
-        t.generics.print(cx),
-        print_where_clause(&t.generics, cx, 0, true),
-        bounds(&t.bounds, true, cx)
-    );
+    wrap_item(w, "trait-alias", |w| {
+        render_attributes_in_pre(w, it, "");
+        write!(
+            w,
+            "trait {}{}{} = {};",
+            it.name.as_ref().unwrap(),
+            t.generics.print(cx),
+            print_where_clause(&t.generics, cx, 0, true),
+            bounds(&t.bounds, true, cx)
+        );
+    });
 
     document(w, cx, it, None);
 
@@ -832,16 +837,17 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
 }
 
 fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
-    w.write_str("<pre class=\"rust opaque\">");
-    render_attributes_in_pre(w, it, "");
-    write!(
-        w,
-        "type {}{}{where_clause} = impl {bounds};</pre>",
-        it.name.as_ref().unwrap(),
-        t.generics.print(cx),
-        where_clause = print_where_clause(&t.generics, cx, 0, true),
-        bounds = bounds(&t.bounds, false, cx),
-    );
+    wrap_item(w, "opaque", |w| {
+        render_attributes_in_pre(w, it, "");
+        write!(
+            w,
+            "type {}{}{where_clause} = impl {bounds};",
+            it.name.as_ref().unwrap(),
+            t.generics.print(cx),
+            where_clause = print_where_clause(&t.generics, cx, 0, true),
+            bounds = bounds(&t.bounds, false, cx),
+        );
+    });
 
     document(w, cx, it, None);
 
@@ -859,19 +865,20 @@ fn item_typedef(
     t: &clean::Typedef,
     is_associated: bool,
 ) {
-    w.write_str("<pre class=\"rust typedef\">");
-    render_attributes_in_pre(w, it, "");
-    if !is_associated {
-        write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
-    }
-    write!(
-        w,
-        "type {}{}{where_clause} = {type_};</pre>",
-        it.name.as_ref().unwrap(),
-        t.generics.print(cx),
-        where_clause = print_where_clause(&t.generics, cx, 0, true),
-        type_ = t.type_.print(cx),
-    );
+    wrap_item(w, "typedef", |w| {
+        render_attributes_in_pre(w, it, "");
+        if !is_associated {
+            write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
+        }
+        write!(
+            w,
+            "type {}{}{where_clause} = {type_};",
+            it.name.as_ref().unwrap(),
+            t.generics.print(cx),
+            where_clause = print_where_clause(&t.generics, cx, 0, true),
+            type_ = t.type_.print(cx),
+        );
+    });
 
     document(w, cx, it, None);
 
@@ -885,10 +892,10 @@ fn item_typedef(
 
 fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
     wrap_into_docblock(w, |w| {
-        w.write_str("<pre class=\"rust union\">");
-        render_attributes_in_pre(w, it, "");
-        render_union(w, it, Some(&s.generics), &s.fields, "", cx);
-        w.write_str("</pre>")
+        wrap_item(w, "union", |w| {
+            render_attributes_in_pre(w, it, "");
+            render_union(w, it, Some(&s.generics), &s.fields, "", cx);
+        });
     });
 
     document(w, cx, it, None);
@@ -934,59 +941,68 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
 
 fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
     wrap_into_docblock(w, |w| {
-        w.write_str("<pre class=\"rust enum\">");
-        render_attributes_in_pre(w, it, "");
-        write!(
-            w,
-            "{}enum {}{}{}",
-            it.visibility.print_with_space(it.def_id, cx),
-            it.name.as_ref().unwrap(),
-            e.generics.print(cx),
-            print_where_clause(&e.generics, cx, 0, true),
-        );
-        if e.variants.is_empty() && !e.variants_stripped {
-            w.write_str(" {}");
-        } else {
-            w.write_str(" {\n");
-            let count_variants = e.variants.len();
-            let toggle = should_hide_fields(count_variants);
-            if toggle {
-                toggle_open(w, format_args!("{} variants", count_variants));
-            }
-            for v in &e.variants {
-                w.write_str("    ");
-                let name = v.name.as_ref().unwrap();
-                match *v.kind {
-                    clean::VariantItem(ref var) => match var {
-                        clean::Variant::CLike => write!(w, "{}", name),
-                        clean::Variant::Tuple(ref tys) => {
-                            write!(w, "{}(", name);
-                            for (i, ty) in tys.iter().enumerate() {
-                                if i > 0 {
-                                    w.write_str(",&nbsp;")
+        wrap_item(w, "enum", |w| {
+            render_attributes_in_pre(w, it, "");
+            write!(
+                w,
+                "{}enum {}{}{}",
+                it.visibility.print_with_space(it.def_id, cx),
+                it.name.as_ref().unwrap(),
+                e.generics.print(cx),
+                print_where_clause(&e.generics, cx, 0, true),
+            );
+            if e.variants.is_empty() && !e.variants_stripped {
+                w.write_str(" {}");
+            } else {
+                w.write_str(" {\n");
+                let count_variants = e.variants.len();
+                let toggle = should_hide_fields(count_variants);
+                if toggle {
+                    toggle_open(w, format_args!("{} variants", count_variants));
+                }
+                for v in &e.variants {
+                    w.write_str("    ");
+                    let name = v.name.as_ref().unwrap();
+                    match *v.kind {
+                        clean::VariantItem(ref var) => match var {
+                            clean::Variant::CLike => write!(w, "{}", name),
+                            clean::Variant::Tuple(ref tys) => {
+                                write!(w, "{}(", name);
+                                for (i, ty) in tys.iter().enumerate() {
+                                    if i > 0 {
+                                        w.write_str(",&nbsp;")
+                                    }
+                                    write!(w, "{}", ty.print(cx));
                                 }
-                                write!(w, "{}", ty.print(cx));
+                                w.write_str(")");
                             }
-                            w.write_str(")");
-                        }
-                        clean::Variant::Struct(ref s) => {
-                            render_struct(w, v, None, s.struct_type, &s.fields, "    ", false, cx);
-                        }
-                    },
-                    _ => unreachable!(),
+                            clean::Variant::Struct(ref s) => {
+                                render_struct(
+                                    w,
+                                    v,
+                                    None,
+                                    s.struct_type,
+                                    &s.fields,
+                                    "    ",
+                                    false,
+                                    cx,
+                                );
+                            }
+                        },
+                        _ => unreachable!(),
+                    }
+                    w.write_str(",\n");
                 }
-                w.write_str(",\n");
-            }
 
-            if e.variants_stripped {
-                w.write_str("    // some variants omitted\n");
-            }
-            if toggle {
-                toggle_close(w);
+                if e.variants_stripped {
+                    w.write_str("    // some variants omitted\n");
+                }
+                if toggle {
+                    toggle_close(w);
+                }
+                w.write_str("}");
             }
-            w.write_str("}");
-        }
-        w.write_str("</pre>")
+        });
     });
 
     document(w, cx, it, None);
@@ -1090,27 +1106,27 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean
     let name = it.name.as_ref().expect("proc-macros always have names");
     match m.kind {
         MacroKind::Bang => {
-            w.push_str("<pre class=\"rust macro\">");
-            write!(w, "{}!() {{ /* proc-macro */ }}", name);
-            w.push_str("</pre>");
+            wrap_item(w, "macro", |w| {
+                write!(w, "{}!() {{ /* proc-macro */ }}", name);
+            });
         }
         MacroKind::Attr => {
-            w.push_str("<pre class=\"rust attr\">");
-            write!(w, "#[{}]", name);
-            w.push_str("</pre>");
+            wrap_item(w, "attr", |w| {
+                write!(w, "#[{}]", name);
+            });
         }
         MacroKind::Derive => {
-            w.push_str("<pre class=\"rust derive\">");
-            write!(w, "#[derive({})]", name);
-            if !m.helpers.is_empty() {
-                w.push_str("\n{\n");
-                w.push_str("    // Attributes available to this derive:\n");
-                for attr in &m.helpers {
-                    writeln!(w, "    #[{}]", attr);
+            wrap_item(w, "derive", |w| {
+                write!(w, "#[derive({})]", name);
+                if !m.helpers.is_empty() {
+                    w.push_str("\n{\n");
+                    w.push_str("    // Attributes available to this derive:\n");
+                    for attr in &m.helpers {
+                        writeln!(w, "    #[{}]", attr);
+                    }
+                    w.push_str("}\n");
                 }
-                w.push_str("}\n");
-            }
-            w.push_str("</pre>");
+            });
         }
     }
     document(w, cx, it, None)
@@ -1122,49 +1138,49 @@ fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
 }
 
 fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
-    w.write_str("<pre class=\"rust const\">");
-    render_attributes_in_code(w, it);
+    wrap_item(w, "const", |w| {
+        render_attributes_in_code(w, it);
 
-    write!(
-        w,
-        "{vis}const {name}: {typ}",
-        vis = it.visibility.print_with_space(it.def_id, cx),
-        name = it.name.as_ref().unwrap(),
-        typ = c.type_.print(cx),
-    );
+        write!(
+            w,
+            "{vis}const {name}: {typ}",
+            vis = it.visibility.print_with_space(it.def_id, cx),
+            name = it.name.as_ref().unwrap(),
+            typ = c.type_.print(cx),
+        );
 
-    let value = c.value(cx.tcx());
-    let is_literal = c.is_literal(cx.tcx());
-    let expr = c.expr(cx.tcx());
-    if value.is_some() || is_literal {
-        write!(w, " = {expr};", expr = Escape(&expr));
-    } else {
-        w.write_str(";");
-    }
+        let value = c.value(cx.tcx());
+        let is_literal = c.is_literal(cx.tcx());
+        let expr = c.expr(cx.tcx());
+        if value.is_some() || is_literal {
+            write!(w, " = {expr};", expr = Escape(&expr));
+        } else {
+            w.write_str(";");
+        }
 
-    if !is_literal {
-        if let Some(value) = &value {
-            let value_lowercase = value.to_lowercase();
-            let expr_lowercase = expr.to_lowercase();
+        if !is_literal {
+            if let Some(value) = &value {
+                let value_lowercase = value.to_lowercase();
+                let expr_lowercase = expr.to_lowercase();
 
-            if value_lowercase != expr_lowercase
-                && value_lowercase.trim_end_matches("i32") != expr_lowercase
-            {
-                write!(w, " // {value}", value = Escape(value));
+                if value_lowercase != expr_lowercase
+                    && value_lowercase.trim_end_matches("i32") != expr_lowercase
+                {
+                    write!(w, " // {value}", value = Escape(value));
+                }
             }
         }
-    }
+    });
 
-    w.write_str("</pre>");
     document(w, cx, it, None)
 }
 
 fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
     wrap_into_docblock(w, |w| {
-        w.write_str("<pre class=\"rust struct\">");
-        render_attributes_in_code(w, it);
-        render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
-        w.write_str("</pre>")
+        wrap_item(w, "struct", |w| {
+            render_attributes_in_code(w, it);
+            render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
+        });
     });
 
     document(w, cx, it, None);
@@ -1213,28 +1229,31 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
 }
 
 fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
-    w.write_str("<pre class=\"rust static\">");
-    render_attributes_in_code(w, it);
-    write!(
-        w,
-        "{vis}static {mutability}{name}: {typ}</pre>",
-        vis = it.visibility.print_with_space(it.def_id, cx),
-        mutability = s.mutability.print_with_space(),
-        name = it.name.as_ref().unwrap(),
-        typ = s.type_.print(cx)
-    );
+    wrap_item(w, "static", |w| {
+        render_attributes_in_code(w, it);
+        write!(
+            w,
+            "{vis}static {mutability}{name}: {typ}",
+            vis = it.visibility.print_with_space(it.def_id, cx),
+            mutability = s.mutability.print_with_space(),
+            name = it.name.as_ref().unwrap(),
+            typ = s.type_.print(cx)
+        );
+    });
     document(w, cx, it, None)
 }
 
 fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
-    w.write_str("<pre class=\"rust foreigntype\">extern {\n");
-    render_attributes_in_code(w, it);
-    write!(
-        w,
-        "    {}type {};\n}}</pre>",
-        it.visibility.print_with_space(it.def_id, cx),
-        it.name.as_ref().unwrap(),
-    );
+    wrap_item(w, "foreigntype", |w| {
+        w.write_str("extern {\n");
+        render_attributes_in_code(w, it);
+        write!(
+            w,
+            "    {}type {};\n}}",
+            it.visibility.print_with_space(it.def_id, cx),
+            it.name.as_ref().unwrap(),
+        );
+    });
 
     document(w, cx, it, None);
 
@@ -1321,6 +1340,15 @@ where
     w.write_str("</div>")
 }
 
+fn wrap_item<F>(w: &mut Buffer, item_name: &str, f: F)
+where
+    F: FnOnce(&mut Buffer),
+{
+    w.write_fmt(format_args!("<pre class=\"rust {}\"><code>", item_name));
+    f(w);
+    w.write_str("</code></pre>");
+}
+
 fn render_stability_since(
     w: &mut Buffer,
     item: &clean::Item,
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 0714de9d565..23ca6eeaf3b 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -249,7 +249,6 @@ code, pre, a.test-arrow, .code-header {
 }
 .docblock pre code, .docblock-short pre code {
 	padding: 0;
-	padding-right: 1ex;
 }
 pre {
 	padding: 14px;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index e02d92b11b8..34fe808dae2 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -294,6 +294,13 @@ fn opts() -> Vec<RustcOptGroup> {
                 "NAME=URL",
             )
         }),
+        unstable("extern-html-root-takes-precedence", |o| {
+            o.optflagmulti(
+                "",
+                "extern-html-root-takes-precedence",
+                "give precedence to `--extern-html-root-url`, not `html_root_url`",
+            )
+        }),
         stable("plugin-path", |o| o.optmulti("", "plugin-path", "removed", "DIR")),
         stable("C", |o| {
             o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]")
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 260e0f8682098faab68af9c608534756ad37836
+Subproject e6c5dd473b7da567dc20ed3a635ca4dd2c6b7fb
diff --git a/src/test/codegen/array-equality.rs b/src/test/codegen/array-equality.rs
index 4b60fa4b0bf..fefc232b490 100644
--- a/src/test/codegen/array-equality.rs
+++ b/src/test/codegen/array-equality.rs
@@ -29,7 +29,7 @@ pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool
     // CHECK-NEXT: start:
     // CHECK-NEXT: bitcast
     // CHECK-NEXT: bitcast
-    // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(i8* nonnull dereferenceable(18) %{{.+}}, i8* nonnull dereferenceable(18) %{{.+}}, i64 18)
+    // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(i8* {{.*}} dereferenceable(18) %{{.+}}, i8* {{.*}} dereferenceable(18) %{{.+}}, i64 18)
     // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
     // CHECK-NEXT: ret i1 %[[EQ]]
     a == b
@@ -41,7 +41,7 @@ pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool {
     // CHECK-NEXT: start:
     // CHECK-NEXT: bitcast
     // CHECK-NEXT: bitcast
-    // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(i8* nonnull dereferenceable(2468) %{{.+}}, i8* nonnull dereferenceable(2468) %{{.+}}, i64 2468)
+    // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(i8* {{.*}} dereferenceable(2468) %{{.+}}, i8* {{.*}} dereferenceable(2468) %{{.+}}, i64 2468)
     // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
     // CHECK-NEXT: ret i1 %[[EQ]]
     a == b
diff --git a/src/test/codegen/issue-83623-SIMD-PartialEq.rs b/src/test/codegen/issue-83623-SIMD-PartialEq.rs
deleted file mode 100644
index b22b7f52402..00000000000
--- a/src/test/codegen/issue-83623-SIMD-PartialEq.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// This test checks that jumps generated by logical operators can be optimized away
-
-// compile-flags: -Copt-level=3
-// only-64bit
-
-#![crate_type="lib"]
-
-pub struct Blueprint {
-    pub fuel_tank_size: u32,
-    pub payload: u32,
-    pub wheel_diameter: u32,
-    pub wheel_width: u32,
-    pub storage: u32,
-}
-
-// && chains should not prevent SIMD optimizations for primitives
-impl PartialEq for Blueprint{
-    fn eq(&self, other: &Self)->bool{
-       // CHECK-NOT: call{{.*}}bcmp
-       // CHECK-NOT: call{{.*}}memcmp
-       // CHECK-NOT: br {{.*}}
-       self.fuel_tank_size == other.fuel_tank_size
-            && self.payload == other.payload
-            && self.wheel_diameter == other.wheel_diameter
-            && self.wheel_width == other.wheel_width
-            && self.storage == other.storage
-    }
-}
-
-#[derive(PartialEq)]
-pub struct Blueprint2 {
-    pub fuel_tank_size: u32,
-    pub payload: u32,
-    pub wheel_diameter: u32,
-    pub wheel_width: u32,
-    pub storage: u32,
-}
-
-// Derived PartialEq should not generate jumps and should use SIMD
-#[no_mangle]
-pub fn partial_eq_should_not_jump(a: &Blueprint2, b:&Blueprint2)->bool{
-    // CHECK-NOT: call{{.*}}bcmp
-    // CHECK-NOT: call{{.*}}memcmp
-    // CHECK-NOT: br {{.*}}
-    a==b
-}
diff --git a/src/test/codegen/naked-noinline.rs b/src/test/codegen/naked-noinline.rs
index d9e6f6c34ec..d576a53826c 100644
--- a/src/test/codegen/naked-noinline.rs
+++ b/src/test/codegen/naked-noinline.rs
@@ -1,5 +1,6 @@
 // Checks that naked functions are never inlined.
 // compile-flags: -O -Zmir-opt-level=3
+// needs-asm-support
 // ignore-wasm32
 #![crate_type = "lib"]
 #![feature(asm)]
diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs
index 9e904fc82ab..cb2d0ef809a 100644
--- a/src/test/codegen/repeat-trusted-len.rs
+++ b/src/test/codegen/repeat-trusted-len.rs
@@ -8,6 +8,6 @@ use std::iter;
 // CHECK-LABEL: @repeat_take_collect
 #[no_mangle]
 pub fn repeat_take_collect() -> Vec<u8> {
-// CHECK: call void @llvm.memset.p0i8.i{{[0-9]+}}(i8* {{(nonnull )?}}align 1{{.*}} %{{[0-9]+}}, i8 42, i{{[0-9]+}} 100000, i1 false)
+// CHECK: call void @llvm.memset.p0i8.i{{[0-9]+}}(i8* {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 42, i{{[0-9]+}} 100000, i1 false)
     iter::repeat(42).take(100000).collect()
 }
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-1.rs b/src/test/incremental/const-generics/hash-tyvid-regression-1.rs
new file mode 100644
index 00000000000..f98ae59ddfe
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-1.rs
@@ -0,0 +1,15 @@
+// revisions: cfail
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+// regression test for #77650
+fn c<T, const N: std::num::NonZeroUsize>()
+where
+    [T; N.get()]: Sized,
+{
+    use std::convert::TryFrom;
+    <[T; N.get()]>::try_from(())
+    //~^ error: the trait bound
+    //~^^ error: mismatched types
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-1.stderr b/src/test/incremental/const-generics/hash-tyvid-regression-1.stderr
new file mode 100644
index 00000000000..cb8ca3abd7f
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-1.stderr
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `[T; _]: From<()>` is not satisfied
+  --> $DIR/hash-tyvid-regression-1.rs:9:5
+   |
+LL |     <[T; N.get()]>::try_from(())
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<()>` is not implemented for `[T; _]`
+   |
+   = note: required because of the requirements on the impl of `Into<[T; _]>` for `()`
+   = note: required because of the requirements on the impl of `TryFrom<()>` for `[T; _]`
+note: required by `try_from`
+  --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
+   |
+LL |     fn try_from(value: T) -> Result<Self, Self::Error>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/hash-tyvid-regression-1.rs:9:5
+   |
+LL |     <[T; N.get()]>::try_from(())
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `Result`
+   |
+   = note: expected unit type `()`
+                   found enum `Result<[T; _], Infallible>`
+help: consider using a semicolon here
+   |
+LL |     <[T; N.get()]>::try_from(());
+   |                                 +
+help: try adding a return type
+   |
+LL | -> Result<[T; _], Infallible> where
+   | +++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-2.rs b/src/test/incremental/const-generics/hash-tyvid-regression-2.rs
new file mode 100644
index 00000000000..22536ff56d7
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-2.rs
@@ -0,0 +1,18 @@
+// revisions: cfail
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+// regression test for #77650
+struct C<T, const N: core::num::NonZeroUsize>([T; N.get()])
+where
+    [T; N.get()]: Sized;
+impl<'a, const N: core::num::NonZeroUsize, A, B: PartialEq<A>> PartialEq<&'a [A]> for C<B, N>
+where
+    [B; N.get()]: Sized,
+{
+    fn eq(&self, other: &&'a [A]) -> bool {
+        self.0 == other
+        //~^ error: can't compare
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-2.stderr b/src/test/incremental/const-generics/hash-tyvid-regression-2.stderr
new file mode 100644
index 00000000000..0e6040ef02e
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-2.stderr
@@ -0,0 +1,11 @@
+error[E0277]: can't compare `[B; _]` with `&&[A]`
+  --> $DIR/hash-tyvid-regression-2.rs:12:16
+   |
+LL |         self.0 == other
+   |                ^^ no implementation for `[B; _] == &&[A]`
+   |
+   = help: the trait `PartialEq<&&[A]>` is not implemented for `[B; _]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-3.rs b/src/test/incremental/const-generics/hash-tyvid-regression-3.rs
new file mode 100644
index 00000000000..76b1ae11c7d
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-3.rs
@@ -0,0 +1,26 @@
+// revisions: cfail
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+// regression test for #79251
+struct Node<const D: usize>
+where
+    SmallVec<{ D * 2 }>: ,
+{
+    keys: SmallVec<{ D * 2 }>,
+}
+
+impl<const D: usize> Node<D>
+where
+    SmallVec<{ D * 2 }>: ,
+{
+    fn new() -> Self {
+        let mut node = Node::new();
+        node.keys.some_function();
+        //~^ error: no method named
+        node
+    }
+}
+
+struct SmallVec<const D: usize> {}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-3.stderr b/src/test/incremental/const-generics/hash-tyvid-regression-3.stderr
new file mode 100644
index 00000000000..555d46756dc
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-3.stderr
@@ -0,0 +1,12 @@
+error[E0599]: no method named `some_function` found for struct `SmallVec` in the current scope
+  --> $DIR/hash-tyvid-regression-3.rs:17:19
+   |
+LL |         node.keys.some_function();
+   |                   ^^^^^^^^^^^^^ method not found in `SmallVec<{ D * 2 }>`
+...
+LL | struct SmallVec<const D: usize> {}
+   | ------------------------------- method `some_function` not found for this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-4.rs b/src/test/incremental/const-generics/hash-tyvid-regression-4.rs
new file mode 100644
index 00000000000..35a675a2ab4
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-4.rs
@@ -0,0 +1,40 @@
+// revisions: cfail
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+// regression test for #79251
+#[derive(Debug)]
+struct Node<K, const D: usize>
+where
+    SmallVec<K, { D * 2 }>: ,
+{
+    keys: SmallVec<K, { D * 2 }>,
+}
+
+impl<K, const D: usize> Node<K, D>
+where
+    SmallVec<K, { D * 2 }>: ,
+{
+    fn new() -> Self {
+        panic!()
+    }
+
+    #[inline(never)]
+    fn split(&mut self, i: usize, k: K, right: bool) -> Node<K, D> {
+        let mut node = Node::new();
+        node.keys.push(k);
+        //~^ error: no method named
+        node
+    }
+}
+
+#[derive(Debug)]
+struct SmallVec<T, const D: usize> {
+    data: [T; D],
+}
+impl<T, const D: usize> SmallVec<T, D> {
+    fn new() -> Self {
+        panic!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-4.stderr b/src/test/incremental/const-generics/hash-tyvid-regression-4.stderr
new file mode 100644
index 00000000000..c9a6715e571
--- /dev/null
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-4.stderr
@@ -0,0 +1,12 @@
+error[E0599]: no method named `push` found for struct `SmallVec` in the current scope
+  --> $DIR/hash-tyvid-regression-4.rs:23:19
+   |
+LL |         node.keys.push(k);
+   |                   ^^^^ method not found in `SmallVec<_, { D * 2 }>`
+...
+LL | struct SmallVec<T, const D: usize> {
+   | ---------------------------------- method `push` not found for this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-1.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-1.rs
new file mode 100644
index 00000000000..a6edbb2e9f9
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-1.rs
@@ -0,0 +1,23 @@
+// revisions: cfail
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features, unused_braces)]
+
+trait Delegates<T> {}
+
+struct FileCap<const Op: bool> {}
+
+fn writes_to_path<C>(cap: &C)
+where
+    C: Delegates<FileCap<{ false }>>,
+{
+    writes_to_specific_path(&cap);
+    //~^ error: the trait bound
+}
+
+fn writes_to_specific_path<C>(cap: &C)
+where
+    C: Delegates<FileCap<{ false }>>,
+{
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-2.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-2.rs
new file mode 100644
index 00000000000..52eeec73b0d
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-2.rs
@@ -0,0 +1,18 @@
+// revisions: rpass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+struct Z;
+const fn one() -> usize {
+    1
+}
+
+fn from_a_to_b<T>(source: [u8; one()]) -> T {
+    todo!()
+}
+
+fn not_main() {
+    let _: &Z = from_a_to_b([0; 1]);
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-3.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-3.rs
new file mode 100644
index 00000000000..11cca942dd6
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-3.rs
@@ -0,0 +1,22 @@
+// revisions: rpass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+use std::{convert::TryFrom, num::NonZeroUsize};
+
+struct A<const N: NonZeroUsize>([u8; N.get()])
+where
+    [u8; N.get()]: Sized;
+
+impl<'a, const N: NonZeroUsize> TryFrom<&'a [u8]> for A<N>
+where
+    [u8; N.get()]: Sized,
+{
+    type Error = ();
+    fn try_from(slice: &'a [u8]) -> Result<A<N>, ()> {
+        let _x = <&[u8; N.get()] as TryFrom<&[u8]>>::try_from(slice);
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-82034.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-82034.rs
new file mode 100644
index 00000000000..1b769d0a30d
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-82034.rs
@@ -0,0 +1,34 @@
+// revisions: rpass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+pub trait IsTrue {}
+pub trait IsFalse {}
+
+pub struct Assert<const CHECK: bool> {}
+
+impl IsTrue for Assert<true> {}
+impl IsFalse for Assert<false> {}
+
+pub struct SliceConstWriter<'a, const N: usize> {
+    ptr: &'a mut [u8],
+}
+impl<'a, const N: usize> SliceConstWriter<'a, { N }> {
+    pub fn from_slice(vec: &'a mut [u8]) -> Self {
+        Self { ptr: vec }
+    }
+
+    pub fn convert<const NN: usize>(mut self) -> SliceConstWriter<'a, { NN }> {
+        SliceConstWriter { ptr: self.ptr }
+    }
+}
+
+impl<'a, const N: usize> SliceConstWriter<'a, { N }>
+where
+    Assert<{ N >= 2 }>: IsTrue,
+{
+    pub fn write_u8(mut self) -> SliceConstWriter<'a, { N - 2 }> {
+        self.convert()
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-1.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-1.rs
new file mode 100644
index 00000000000..20d4993774d
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-1.rs
@@ -0,0 +1,23 @@
+// revisions: rpass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+pub struct Ref<'a, const NUM: usize>(&'a i32);
+
+impl<'a, const NUM: usize> Ref<'a, NUM> {
+    pub fn foo<const A: usize>(r: Ref<'a, A>) -> Self
+    where
+        ([(); NUM - A], [(); A - NUM]): Sized,
+    {
+        Self::bar(r)
+    }
+
+    pub fn bar<const A: usize>(r: Ref<'a, A>) -> Self
+    where
+        ([(); NUM - A], [(); A - NUM]): Sized,
+    {
+        Self(r.0)
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-2.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-2.rs
new file mode 100644
index 00000000000..be7ad6d1fa0
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-2.rs
@@ -0,0 +1,14 @@
+// revisions: cfail
+#![allow(incomplete_features)]
+#![feature(const_generics, const_evaluatable_checked)]
+
+pub struct Ref<'a>(&'a i32);
+
+impl<'a> Ref<'a> {
+    pub fn foo<const A: usize>() -> [(); A - 0] {
+        Self::foo()
+        //~^ error: type annotations needed
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-3.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-3.rs
new file mode 100644
index 00000000000..af4f209c904
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-85031-3.rs
@@ -0,0 +1,25 @@
+// revisions: rpass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+fn test<const SIZE: usize>() {}
+
+trait SomeTrait {
+    const SIZE: usize;
+}
+
+struct A<'a, T> {
+    some_ref: &'a str,
+    _maker: core::marker::PhantomData<T>,
+}
+
+impl<'a, T: SomeTrait> A<'a, T>
+where
+    [(); T::SIZE]: ,
+{
+    fn call_test() {
+        test::<{ T::SIZE }>();
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-86953.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-86953.rs
new file mode 100644
index 00000000000..ba863369626
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-86953.rs
@@ -0,0 +1,16 @@
+// revisions: rpass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+struct Foo;
+impl<'a> std::ops::Add<&'a Foo> for Foo
+where
+    [(); 0 + 0]: Sized,
+{
+    type Output = ();
+    fn add(self, _: &Foo) -> Self::Output {
+        loop {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs
new file mode 100644
index 00000000000..da713631cc1
--- /dev/null
+++ b/src/test/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs
@@ -0,0 +1,28 @@
+// revisions: cfail
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features, unused_braces)]
+
+struct Buffer<T, const S: usize>
+where
+    [(); { S * 2 }]: Default,
+{
+    data: [T; { S * 2 }],
+}
+
+struct BufferIter<'a, T, const S: usize>(&'a Buffer<T, S>)
+where
+    [(); { S * 2 }]: Default;
+
+impl<'a, T, const S: usize> Iterator for BufferIter<'a, T, S> {
+    //~^ error: the trait bound
+    //~^^ error: unconstrained generic constant
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        //~^ error: the trait bound
+        //~^^ error: unconstrained generic constant
+        None
+    }
+}
+
+fn main() {}
diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs
index c9a3de1f6ae..2d547f1748c 100644
--- a/src/test/incremental/hashes/trait_impls.rs
+++ b/src/test/incremental/hashes/trait_impls.rs
@@ -62,7 +62,7 @@ impl ChangeMethodBodyTrait for Foo {
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl ChangeMethodBodyTrait for Foo {
-    #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
     fn method_name() {
         ()
diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
index 19af626c49f..1b7c51b3954 100644
--- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
@@ -29,7 +29,7 @@
       }
   
       bb2: {
-          _0 = const ();                   // scope 0 at $DIR/control-flow-simplification.rs:14:6: 14:6
+          nop;                             // scope 0 at $DIR/control-flow-simplification.rs:14:6: 14:6
           StorageDead(_1);                 // scope 0 at $DIR/control-flow-simplification.rs:14:5: 14:6
           return;                          // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2
       }
diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir
index c2f75e5daee..30512d0bbe8 100644
--- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir
+++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir
@@ -4,7 +4,6 @@ fn hello() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/control-flow-simplification.rs:11:14: 11:14
 
     bb0: {
-        _0 = const ();                   // scope 0 at $DIR/control-flow-simplification.rs:14:6: 14:6
         return;                          // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2
     }
 }
diff --git a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff
index 8793af5c074..546a95a86fa 100644
--- a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff
+++ b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff
@@ -14,7 +14,6 @@
           StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11
           _3 = move _1;                    // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11
-          nop;                             // scope 1 at $DIR/remove_unneeded_drops.rs:21:5: 21:12
           drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $DIR/remove_unneeded_drops.rs:21:5: 21:12
       }
   
diff --git a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff
index 2377abdb153..b42813447b1 100644
--- a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff
+++ b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff
@@ -14,7 +14,6 @@
           StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11
           _3 = move _1;                    // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11
-          nop;                             // scope 1 at $DIR/remove_unneeded_drops.rs:9:5: 9:12
           drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $DIR/remove_unneeded_drops.rs:9:5: 9:12
       }
   
diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
index 75bd732e3c0..ee52254f08b 100644
--- a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
+++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
@@ -14,7 +14,6 @@
           StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11
           _3 = _1;                         // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11
--         nop;                             // scope 1 at $DIR/remove_unneeded_drops.rs:4:5: 4:12
 -         drop(_3) -> bb1;                 // scope 1 at $DIR/remove_unneeded_drops.rs:4:5: 4:12
 -     }
 - 
diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
index b3da2cfb24c..21bc90b0eb7 100644
--- a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
+++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
@@ -14,7 +14,6 @@
           StorageLive(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12
           StorageLive(_3);                 // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11
           _3 = _1;                         // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11
--         nop;                             // scope 1 at $DIR/remove_unneeded_drops.rs:14:5: 14:12
 -         drop(_3) -> bb1;                 // scope 1 at $DIR/remove_unneeded_drops.rs:14:5: 14:12
 -     }
 - 
diff --git a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
index 49a57832267..41a6fe30412 100644
--- a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
@@ -9,8 +9,8 @@
       let mut _4: isize;                   // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
       let mut _5: isize;                   // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
       let _6: u8;                          // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19
-      let mut _7: bool;                    // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
-      let mut _8: u8;                      // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
+-     let mut _7: bool;                    // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
+-     let mut _8: u8;                      // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
       scope 1 {
           debug a => _6;                   // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19
       }
@@ -26,51 +26,32 @@
           StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69
           StorageDead(_2);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69
           _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
-          switchInt(move _5) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
+          switchInt(move _5) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
       }
   
       bb1: {
-          _0 = const ();                   // scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:6: 8:6
-          goto -> bb7;                     // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6
-      }
-  
-      bb2: {
           _4 = discriminant((_1.1: std::option::Option<T>)); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
-          switchInt(move _4) -> [0_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
+          switchInt(move _4) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
       }
   
-      bb3: {
+      bb2: {
           StorageLive(_6);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19
           _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19
-          StorageLive(_7);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
-          StorageLive(_8);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
-          _8 = _6;                         // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
-          _7 = Gt(move _8, const 42_u8);   // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
-          StorageDead(_8);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20
-          switchInt(move _7) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10
-      }
-  
-      bb4: {
-          _0 = const ();                   // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:21: 7:10
-          goto -> bb6;                     // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10
-      }
-  
-      bb5: {
-          _0 = const ();                   // scope 0 at $DIR/simplify-locals-fixedpoint.rs:7:10: 7:10
-          goto -> bb6;                     // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10
+-         StorageLive(_7);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
+-         StorageLive(_8);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
+-         _8 = _6;                         // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
+-         _7 = Gt(move _8, const 42_u8);   // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
+-         StorageDead(_8);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20
+-         StorageDead(_7);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:7:9: 7:10
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6
       }
   
-      bb6: {
-          StorageDead(_7);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:7:9: 7:10
-          goto -> bb7;                     // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6
-      }
-  
-      bb7: {
+      bb3: {
           StorageDead(_6);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6
-          drop(_1) -> bb8;                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2
+          drop(_1) -> bb4;                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2
       }
   
-      bb8: {
+      bb4: {
           StorageDead(_1);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:2: 9:2
       }
diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile
index 7d9121ee2f8..1ff1ffcc4b0 100644
--- a/src/test/run-make-fulldeps/coverage-llvmir/Makefile
+++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile
@@ -22,7 +22,6 @@ DEFINE_INTERNAL=define internal
 ifdef IS_WINDOWS
 	LLVM_FILECHECK_OPTIONS=\
 		-check-prefixes=CHECK,WINDOWS \
-		-DPRIVATE_GLOBAL='internal global' \
 		-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
 		-DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \
 		-DINSTR_PROF_DATA='.lprfd$$M' \
@@ -36,7 +35,6 @@ ifdef IS_WINDOWS
 else
 	LLVM_FILECHECK_OPTIONS=\
 		-check-prefixes=CHECK \
-		-DPRIVATE_GLOBAL='private global' \
 		-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
 		-DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \
 		-DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \
diff --git a/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt
index a312ec48e84..8e5f2104687 100644
--- a/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt
+++ b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt
@@ -11,27 +11,25 @@ CHECK-SAME:   section "[[INSTR_PROF_COVMAP]]", align 8
 
 WINDOWS:      @__llvm_profile_runtime = external global i32
 
-CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]]
-CHECK-SAME:   section "[[INSTR_PROF_CNTS]]", align 8
+CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
+CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
 
-CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]]
+CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
 CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
-CHECK-SAME:   section "[[INSTR_PROF_DATA]]", align 8
+CHECK-SAME:   section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
 
-CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]]
-CHECK-SAME:   section "[[INSTR_PROF_CNTS]]", align 8
+CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
+CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
 
-CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]]
+CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
 CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog4main,
-CHECK-SAME:   section "[[INSTR_PROF_DATA]]", align 8
+CHECK-SAME:   section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
 
 CHECK:        @__llvm_prf_nm = private constant
 CHECK-SAME:   section "[[INSTR_PROF_NAME]]", align 1
 
 CHECK:        @llvm.used = appending global
 CHECK-SAME:   i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*)
-WINDOWS-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*)
-CHECK-SAME:   i8* bitcast ({ {{.*}} }* @__profd__R{{[a-zA-Z0-9_]*}}testprog4main to i8*)
 CHECK-SAME:   i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0)
 CHECK-SAME:   section "llvm.metadata"
 
diff --git a/src/test/run-make/const_fn_mir/dump.mir b/src/test/run-make/const_fn_mir/dump.mir
index 45d018cf305..724b2630083 100644
--- a/src/test/run-make/const_fn_mir/dump.mir
+++ b/src/test/run-make/const_fn_mir/dump.mir
@@ -12,7 +12,6 @@ fn main() -> () {
     }
 
     bb1: {
-        _0 = const ();                   // scope 0 at main.rs:8:11: 10:2
         return;                          // scope 0 at main.rs:10:2: 10:2
     }
 }
diff --git a/src/test/rustdoc-gui/code-tags.goml b/src/test/rustdoc-gui/code-tags.goml
new file mode 100644
index 00000000000..200569a28d4
--- /dev/null
+++ b/src/test/rustdoc-gui/code-tags.goml
@@ -0,0 +1,20 @@
+// This test ensures that items and documentation code blocks are wrapped in <pre><code>
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+size: (1080, 600)
+// There should be three doc codeblocks
+// Check that their content is inside <pre><code>
+assert-count: (".example-wrap pre > code", 3)
+// Check that function signature is inside <pre><code>
+assert: "pre.rust.fn > code"
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert: "pre.rust.struct > code"
+
+goto: file://|DOC_PATH|/test_docs/enum.AnEnum.html
+assert: "pre.rust.enum > code"
+
+goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html
+assert: "pre.rust.trait > code"
+
+goto: file://|DOC_PATH|/test_docs/type.SomeType.html
+assert: "pre.rust.typedef > code"
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index d7bae93c211..5a49807e180 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -12,4 +12,4 @@ assert-attribute: (".line-numbers > span:nth-child(5)", {"class": "line-highligh
 assert-attribute: (".line-numbers > span:nth-child(6)", {"class": "line-highlighted"})
 assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
 // This is to ensure that the content is correctly align with the line numbers.
-compare-elements-position: ("//*[@id='1']", ".rust > span", ("y"))
+compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
diff --git a/src/test/rustdoc/auxiliary/html_root.rs b/src/test/rustdoc/auxiliary/html_root.rs
new file mode 100644
index 00000000000..4eb0b700f8f
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/html_root.rs
@@ -0,0 +1,2 @@
+#![doc(html_root_url="https://example.com/html_root")]
+pub fn foo() {}
diff --git a/src/test/rustdoc/auxiliary/no_html_root.rs b/src/test/rustdoc/auxiliary/no_html_root.rs
new file mode 100644
index 00000000000..c5c0bc606cd
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/no_html_root.rs
@@ -0,0 +1 @@
+pub fn bar() {}
diff --git a/src/test/rustdoc/extern-html-root-url-precedence.rs b/src/test/rustdoc/extern-html-root-url-precedence.rs
new file mode 100644
index 00000000000..def6767ea47
--- /dev/null
+++ b/src/test/rustdoc/extern-html-root-url-precedence.rs
@@ -0,0 +1,7 @@
+// compile-flags:-Z unstable-options --extern-html-root-url core=https://example.com/core/0.1.0 --extern-html-root-takes-precedence
+
+// @has extern_html_root_url_precedence/index.html
+// --extern-html-root should take precedence if `--takes-precedence` is passed
+// @has - '//a/@href' 'https://example.com/core/0.1.0/core/iter/index.html'
+#[doc(no_inline)]
+pub use std::iter;
diff --git a/src/test/rustdoc/extern-html-root-url.rs b/src/test/rustdoc/extern-html-root-url.rs
index 60b7b28ae4a..17eedcf2ab8 100644
--- a/src/test/rustdoc/extern-html-root-url.rs
+++ b/src/test/rustdoc/extern-html-root-url.rs
@@ -1,6 +1,18 @@
-// compile-flags:-Z unstable-options --extern-html-root-url core=https://example.com/core/0.1.0
+// compile-flags:-Z unstable-options --extern-html-root-url html_root=https://example.com/override --extern-html-root-url no_html_root=https://example.com/override
+// aux-build:html_root.rs
+// aux-build:no_html_root.rs
+// NOTE: intentionally does not build any auxiliary docs
+
+extern crate html_root;
+extern crate no_html_root;
 
 // @has extern_html_root_url/index.html
-// @has - '//a/@href' 'https://example.com/core/0.1.0/core/iter/index.html'
+// `html_root_url` should override `--extern-html-root-url`
+// @has - '//a/@href' 'https://example.com/html_root/html_root/fn.foo.html'
+#[doc(no_inline)]
+pub use html_root::foo;
+
 #[doc(no_inline)]
-pub use std::iter;
+// `--extern-html-root-url` should apply if no `html_root_url` is given
+// @has - '//a/@href' 'https://example.com/override/no_html_root/fn.bar.html'
+pub use no_html_root::bar;
diff --git a/src/test/ui/closures/2229_closure_analysis/issue-87987.rs b/src/test/ui/closures/2229_closure_analysis/issue-87987.rs
new file mode 100644
index 00000000000..5dc2cb7e710
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/issue-87987.rs
@@ -0,0 +1,30 @@
+// run-pass
+// edition:2021
+
+struct Props {
+    field_1: u32, //~ WARNING: field is never read: `field_1`
+    field_2: u32, //~ WARNING: field is never read: `field_2`
+}
+
+fn main() {
+    // Test 1
+    let props_2 = Props { //~ WARNING: unused variable: `props_2`
+        field_1: 1,
+        field_2: 1,
+    };
+
+    let _ = || {
+        let _: Props = props_2;
+    };
+
+    // Test 2
+    let mut arr = [1, 3, 4, 5];
+
+    let mref = &mut arr;
+
+    let _c = || match arr {
+        [_, _, _, _] => println!("A")
+    };
+
+    println!("{:#?}", mref);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/issue-87987.stderr b/src/test/ui/closures/2229_closure_analysis/issue-87987.stderr
new file mode 100644
index 00000000000..aa7012c3618
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/issue-87987.stderr
@@ -0,0 +1,24 @@
+warning: unused variable: `props_2`
+  --> $DIR/issue-87987.rs:11:9
+   |
+LL |     let props_2 = Props {
+   |         ^^^^^^^ help: if this is intentional, prefix it with an underscore: `_props_2`
+   |
+   = note: `#[warn(unused_variables)]` on by default
+
+warning: field is never read: `field_1`
+  --> $DIR/issue-87987.rs:5:5
+   |
+LL |     field_1: u32,
+   |     ^^^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: field is never read: `field_2`
+  --> $DIR/issue-87987.rs:6:5
+   |
+LL |     field_2: u32,
+   |     ^^^^^^^^^^^^
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/issue-87988.rs b/src/test/ui/closures/2229_closure_analysis/issue-87988.rs
new file mode 100644
index 00000000000..27e7fabf11a
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/issue-87988.rs
@@ -0,0 +1,19 @@
+// run-pass
+// edition:2021
+
+const LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: i32 = 0x01;
+const LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: i32 = 0x02;
+
+pub fn hotplug_callback(event: i32) {
+    let _ = || {
+        match event {
+            LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED => (),
+            LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT => (),
+            _ => (),
+        };
+    };
+}
+
+fn main() {
+    hotplug_callback(1);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/match-edge-cases.rs b/src/test/ui/closures/2229_closure_analysis/match-edge-cases.rs
new file mode 100644
index 00000000000..914ebbe26a5
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/match-edge-cases.rs
@@ -0,0 +1,44 @@
+// run-pass
+// edition:2021
+
+const PATTERN_REF: &str = "Hello World";
+const NUMBER: i32 = 30;
+const NUMBER_POINTER: *const i32 = &NUMBER;
+
+pub fn edge_case_ref(event: &str) {
+    let _ = || {
+        match event {
+            PATTERN_REF => (),
+            _ => (),
+        };
+    };
+}
+
+pub fn edge_case_str(event: String) {
+    let _ = || {
+        match event.as_str() {
+            "hello" => (),
+            _ => (),
+        };
+    };
+}
+
+pub fn edge_case_raw_ptr(event: *const i32) {
+    let _ = || {
+        match event {
+            NUMBER_POINTER => (),
+            _ => (),
+        };
+    };
+}
+
+pub fn edge_case_char(event: char) {
+    let _ = || {
+        match event {
+            'a' => (),
+            _ => (),
+        };
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/codegen/issue-88043-bb-does-not-have-terminator.rs b/src/test/ui/codegen/issue-88043-bb-does-not-have-terminator.rs
index 1a6aadc662b..38dfca347c8 100644
--- a/src/test/ui/codegen/issue-88043-bb-does-not-have-terminator.rs
+++ b/src/test/ui/codegen/issue-88043-bb-does-not-have-terminator.rs
@@ -22,4 +22,14 @@ fn take_until(terminate: impl Fn() -> bool) {
 // CHECK-LABEL: @main
 fn main() {
     take_until(|| true);
+    f(None);
 }
+
+fn f(_a: Option<String>) -> Option<u32> {
+    loop {
+        g();
+        ()
+    }
+}
+
+fn g() -> Option<u32> { None }
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
index 78cf25308ff..ab0256a986d 100644
--- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
@@ -14,5 +14,4 @@ impl PrintName {
 
 fn main() {
     let _ = PrintName::VOID;
-    //~^ ERROR erroneous constant used
 }
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
index 08560948309..f1c606a8a2e 100644
--- a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
@@ -6,12 +6,6 @@ LL |     const VOID: ! = panic!();
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0080]: erroneous constant used
-  --> $DIR/panic-assoc-never-type.rs:16:13
-   |
-LL |     let _ = PrintName::VOID;
-   |             ^^^^^^^^^^^^^^^ referenced constant has errors
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/drop-bounds/drop-bounds.stderr b/src/test/ui/drop-bounds/drop-bounds.stderr
index 15ba4c9a649..3ffb855a55d 100644
--- a/src/test/ui/drop-bounds/drop-bounds.stderr
+++ b/src/test/ui/drop-bounds/drop-bounds.stderr
@@ -1,4 +1,4 @@
-error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
   --> $DIR/drop-bounds.rs:2:11
    |
 LL | fn foo<T: Drop>() {}
@@ -10,37 +10,37 @@ note: the lint level is defined here
 LL | #![deny(drop_bounds)]
    |         ^^^^^^^^^^^
 
-error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+error: bounds on `U: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
   --> $DIR/drop-bounds.rs:5:8
    |
 LL |     U: Drop,
    |        ^^^^
 
-error: bounds on `impl Drop: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+error: bounds on `impl Drop: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
   --> $DIR/drop-bounds.rs:8:17
    |
 LL | fn baz(_x: impl Drop) {}
    |                 ^^^^
 
-error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
   --> $DIR/drop-bounds.rs:9:15
    |
 LL | struct Foo<T: Drop> {
    |               ^^^^
 
-error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+error: bounds on `U: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
   --> $DIR/drop-bounds.rs:12:24
    |
 LL | struct Bar<U> where U: Drop {
    |                        ^^^^
 
-error: bounds on `Self: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+error: bounds on `Self: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
   --> $DIR/drop-bounds.rs:15:12
    |
 LL | trait Baz: Drop {
    |            ^^^^
 
-error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
   --> $DIR/drop-bounds.rs:17:9
    |
 LL | impl<T: Drop> Baz for T {
diff --git a/src/test/ui/dst/dst-rvalue.rs b/src/test/ui/dst/dst-rvalue.rs
index aa028396be4..b52a95a701f 100644
--- a/src/test/ui/dst/dst-rvalue.rs
+++ b/src/test/ui/dst/dst-rvalue.rs
@@ -4,11 +4,9 @@
 
 pub fn main() {
     let _x: Box<str> = box *"hello world";
-    //~^ ERROR E0161
-    //~^^ ERROR cannot move out of a shared reference
+    //~^ ERROR E0277
 
     let array: &[isize] = &[1, 2, 3];
     let _x: Box<[isize]> = box *array;
-    //~^ ERROR E0161
-    //~^^ ERROR cannot move out of type `[isize]`, a non-copy slice
+    //~^ ERROR E0277
 }
diff --git a/src/test/ui/dst/dst-rvalue.stderr b/src/test/ui/dst/dst-rvalue.stderr
index 6a51c517558..15830636b51 100644
--- a/src/test/ui/dst/dst-rvalue.stderr
+++ b/src/test/ui/dst/dst-rvalue.stderr
@@ -1,31 +1,21 @@
-error[E0161]: cannot move a value of type str: the size of str cannot be statically determined
+error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/dst-rvalue.rs:6:28
    |
 LL |     let _x: Box<str> = box *"hello world";
-   |                            ^^^^^^^^^^^^^^
-
-error[E0161]: cannot move a value of type [isize]: the size of [isize] cannot be statically determined
-  --> $DIR/dst-rvalue.rs:11:32
+   |                            ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-LL |     let _x: Box<[isize]> = box *array;
-   |                                ^^^^^^
+   = help: the trait `Sized` is not implemented for `str`
+   = note: the type of a box expression must have a statically known size
 
-error[E0507]: cannot move out of a shared reference
-  --> $DIR/dst-rvalue.rs:6:28
-   |
-LL |     let _x: Box<str> = box *"hello world";
-   |                            ^^^^^^^^^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait
-
-error[E0508]: cannot move out of type `[isize]`, a non-copy slice
-  --> $DIR/dst-rvalue.rs:11:32
+error[E0277]: the size for values of type `[isize]` cannot be known at compilation time
+  --> $DIR/dst-rvalue.rs:10:32
    |
 LL |     let _x: Box<[isize]> = box *array;
-   |                                ^^^^^^
-   |                                |
-   |                                cannot move out of here
-   |                                move occurs because `*array` has type `[isize]`, which does not implement the `Copy` trait
+   |                                ^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[isize]`
+   = note: the type of a box expression must have a statically known size
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0161, E0507, E0508.
-For more information about an error, try `rustc --explain E0161`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/enum/enum-discrim-autosizing.rs b/src/test/ui/enum/enum-discrim-autosizing.rs
index e9bb9275971..473a0ad6f7a 100644
--- a/src/test/ui/enum/enum-discrim-autosizing.rs
+++ b/src/test/ui/enum/enum-discrim-autosizing.rs
@@ -4,8 +4,10 @@
 // so force the repr.
 #[cfg_attr(not(target_pointer_width = "32"), repr(i32))]
 enum Eu64 {
-    Au64 = 0,
-    Bu64 = 0x8000_0000_0000_0000 //~ERROR already exists
+    Au64 = 0, //~NOTE first use of `0`
+    Bu64 = 0x8000_0000_0000_0000
+    //~^ ERROR discriminant value `0` already exists
+    //~| NOTE enum already has `0` (overflowed from `9223372036854775808`)
 }
 
 fn main() {}
diff --git a/src/test/ui/enum/enum-discrim-autosizing.stderr b/src/test/ui/enum/enum-discrim-autosizing.stderr
index 8848f984cfb..a0f39098a2e 100644
--- a/src/test/ui/enum/enum-discrim-autosizing.stderr
+++ b/src/test/ui/enum/enum-discrim-autosizing.stderr
@@ -4,7 +4,7 @@ error[E0081]: discriminant value `0` already exists
 LL |     Au64 = 0,
    |            - first use of `0`
 LL |     Bu64 = 0x8000_0000_0000_0000
-   |            ^^^^^^^^^^^^^^^^^^^^^ enum already has `0`
+   |            ^^^^^^^^^^^^^^^^^^^^^ enum already has `0` (overflowed from `9223372036854775808`)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0081.rs b/src/test/ui/error-codes/E0081.rs
index 33c8c14306b..255e05ced19 100644
--- a/src/test/ui/error-codes/E0081.rs
+++ b/src/test/ui/error-codes/E0081.rs
@@ -1,9 +1,20 @@
 enum Enum {
     P = 3,
+    //~^ NOTE first use of `3`
     X = 3,
     //~^ ERROR discriminant value `3` already exists
+    //~| NOTE enum already has `3`
     Y = 5
 }
 
+#[repr(u8)]
+enum EnumOverflowRepr {
+    P = 257,
+    //~^ NOTE first use of `1` (overflowed from `257`)
+    X = 513,
+    //~^ ERROR discriminant value `1` already exists
+    //~| NOTE enum already has `1` (overflowed from `513`)
+}
+
 fn main() {
 }
diff --git a/src/test/ui/error-codes/E0081.stderr b/src/test/ui/error-codes/E0081.stderr
index 0b3d351e1ac..9b279bb0214 100644
--- a/src/test/ui/error-codes/E0081.stderr
+++ b/src/test/ui/error-codes/E0081.stderr
@@ -1,11 +1,21 @@
 error[E0081]: discriminant value `3` already exists
-  --> $DIR/E0081.rs:3:9
+  --> $DIR/E0081.rs:4:9
    |
 LL |     P = 3,
    |         - first use of `3`
+LL |
 LL |     X = 3,
    |         ^ enum already has `3`
 
-error: aborting due to previous error
+error[E0081]: discriminant value `1` already exists
+  --> $DIR/E0081.rs:14:9
+   |
+LL |     P = 257,
+   |         --- first use of `1` (overflowed from `257`)
+LL |
+LL |     X = 513,
+   |         ^^^ enum already has `1` (overflowed from `513`)
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0081`.
diff --git a/src/test/ui/error-codes/E0161.edition.stderr b/src/test/ui/error-codes/E0161.edition.stderr
index 536a81a4bc6..6beb29c57d5 100644
--- a/src/test/ui/error-codes/E0161.edition.stderr
+++ b/src/test/ui/error-codes/E0161.edition.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:9
+error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
+  --> $DIR/E0161.rs:29:5
    |
-LL |     box *x;
-   |         ^^
+LL |     x.f();
+   |     ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0161.editionul.stderr b/src/test/ui/error-codes/E0161.editionul.stderr
deleted file mode 100644
index 2baba998f12..00000000000
--- a/src/test/ui/error-codes/E0161.editionul.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:5
-   |
-LL |     box *x;
-   |     ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.migrate.stderr b/src/test/ui/error-codes/E0161.migrate.stderr
index 536a81a4bc6..6beb29c57d5 100644
--- a/src/test/ui/error-codes/E0161.migrate.stderr
+++ b/src/test/ui/error-codes/E0161.migrate.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:9
+error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
+  --> $DIR/E0161.rs:29:5
    |
-LL |     box *x;
-   |         ^^
+LL |     x.f();
+   |     ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0161.migrateul.stderr b/src/test/ui/error-codes/E0161.migrateul.stderr
deleted file mode 100644
index 2baba998f12..00000000000
--- a/src/test/ui/error-codes/E0161.migrateul.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:5
-   |
-LL |     box *x;
-   |     ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.nll.stderr b/src/test/ui/error-codes/E0161.nll.stderr
index 536a81a4bc6..6beb29c57d5 100644
--- a/src/test/ui/error-codes/E0161.nll.stderr
+++ b/src/test/ui/error-codes/E0161.nll.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:9
+error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
+  --> $DIR/E0161.rs:29:5
    |
-LL |     box *x;
-   |         ^^
+LL |     x.f();
+   |     ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0161.nllul.stderr b/src/test/ui/error-codes/E0161.nllul.stderr
deleted file mode 100644
index 2baba998f12..00000000000
--- a/src/test/ui/error-codes/E0161.nllul.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:5
-   |
-LL |     box *x;
-   |     ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.rs b/src/test/ui/error-codes/E0161.rs
index e0f5776424e..ba74529e4b6 100644
--- a/src/test/ui/error-codes/E0161.rs
+++ b/src/test/ui/error-codes/E0161.rs
@@ -8,6 +8,10 @@
 //[edition]edition:2018
 //[zflagsul]compile-flags: -Z borrowck=migrate
 //[editionul]edition:2018
+//[migrateul] check-pass
+//[nllul] check-pass
+//[zflagsul] check-pass
+//[editionul] check-pass
 
 #![allow(incomplete_features)]
 #![cfg_attr(nll, feature(nll))]
@@ -16,12 +20,14 @@
 #![cfg_attr(zflagsul, feature(unsized_locals))]
 #![cfg_attr(nllul, feature(unsized_locals))]
 #![cfg_attr(editionul, feature(unsized_locals))]
-#![feature(box_syntax)]
 
-fn foo(x: Box<[i32]>) {
-    box *x;
+trait Bar {
+    fn f(self);
+}
+
+fn foo(x: Box<dyn Bar>) {
+    x.f();
     //[migrate,nll,zflags,edition]~^ ERROR E0161
-    //[migrateul,nllul,zflagsul,editionul]~^^ ERROR E0161
 }
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0161.zflags.stderr b/src/test/ui/error-codes/E0161.zflags.stderr
index 536a81a4bc6..6beb29c57d5 100644
--- a/src/test/ui/error-codes/E0161.zflags.stderr
+++ b/src/test/ui/error-codes/E0161.zflags.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:9
+error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
+  --> $DIR/E0161.rs:29:5
    |
-LL |     box *x;
-   |         ^^
+LL |     x.f();
+   |     ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0161.zflagsul.stderr b/src/test/ui/error-codes/E0161.zflagsul.stderr
deleted file mode 100644
index 2baba998f12..00000000000
--- a/src/test/ui/error-codes/E0161.zflagsul.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
-  --> $DIR/E0161.rs:22:5
-   |
-LL |     box *x;
-   |     ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.rs b/src/test/ui/feature-gates/feature-gate-global_asm.rs
index 8c9f22e9752..1420eef299b 100644
--- a/src/test/ui/feature-gates/feature-gate-global_asm.rs
+++ b/src/test/ui/feature-gates/feature-gate-global_asm.rs
@@ -1,3 +1,5 @@
+// needs-asm-support
+
 global_asm!(""); //~ ERROR `global_asm!` is not stable
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.stderr b/src/test/ui/feature-gates/feature-gate-global_asm.stderr
index e07fbf00d57..7c4d3e3e6e5 100644
--- a/src/test/ui/feature-gates/feature-gate-global_asm.stderr
+++ b/src/test/ui/feature-gates/feature-gate-global_asm.stderr
@@ -1,5 +1,5 @@
 error[E0658]: use of unstable library feature 'global_asm': `global_asm!` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-global_asm.rs:1:1
+  --> $DIR/feature-gate-global_asm.rs:3:1
    |
 LL | global_asm!("");
    | ^^^^^^^^^^
diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs b/src/test/ui/lint/force-warn/allow-warnings.rs
index 0e8a65a4117..6ee5ba67932 100644
--- a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs
+++ b/src/test/ui/lint/force-warn/allow-warnings.rs
@@ -1,3 +1,5 @@
+// --force-warn $LINT causes $LINT (which is warn-by-default) to warn
+// despite allowing all warnings in module
 // compile-flags: --force-warn dead_code -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.stderr b/src/test/ui/lint/force-warn/allow-warnings.stderr
index fced147254e..cac2b4e9189 100644
--- a/src/test/ui/lint/force-warn/force-allowed-warning.stderr
+++ b/src/test/ui/lint/force-warn/allow-warnings.stderr
@@ -1,5 +1,5 @@
 warning: function is never used: `dead_function`
-  --> $DIR/force-allowed-warning.rs:6:4
+  --> $DIR/allow-warnings.rs:8:4
    |
 LL | fn dead_function() {}
    |    ^^^^^^^^^^^^^
diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs b/src/test/ui/lint/force-warn/allowed-by-default-lint.rs
index 4799429ea2c..fd0b886d84d 100644
--- a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs
+++ b/src/test/ui/lint/force-warn/allowed-by-default-lint.rs
@@ -1,3 +1,4 @@
+// --force-warn $LINT causes $LINT (which is allow-by-default) to warn
 // compile-flags: --force-warn elided_lifetimes_in_paths -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
index 05513de81d1..baa47cbb10f 100644
--- a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
@@ -1,5 +1,5 @@
 warning: hidden lifetime parameters in types are deprecated
-  --> $DIR/force-allowed-by-default-lint.rs:8:12
+  --> $DIR/allowed-by-default-lint.rs:9:12
    |
 LL | fn foo(x: &Foo) {}
    |            ^^^- help: indicate the anonymous lifetime: `<'_>`
diff --git a/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs
new file mode 100644
index 00000000000..3fab9148392
--- /dev/null
+++ b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs
@@ -0,0 +1,10 @@
+// --force-warn $LINT causes $LINT (which is deny-by-default) to warn
+// despite $LINT being allowed on command line
+// compile-flags: -A const_err --force-warn const_err -Zunstable-options
+// check-pass
+
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr
index dd4f88a3b53..af6308f0d1b 100644
--- a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr
@@ -1,5 +1,5 @@
 warning: any use of this value will cause an error
-  --> $DIR/force-allowed-deny-by-default-lint.rs:5:16
+  --> $DIR/allowed-cli-deny-by-default-lint.rs:6:16
    |
 LL | const C: i32 = 1 / 0;
    | ---------------^^^^^-
diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.rs
index 8331df02da7..82a584ac972 100644
--- a/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs
+++ b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.rs
@@ -1,6 +1,9 @@
+// --force-warn $LINT causes $LINT (which is deny-by-default) to warn
+// despite $LINT being allowed in module
 // compile-flags: --force-warn const_err -Zunstable-options
 // check-pass
 
+#![allow(const_err)]
 const C: i32 = 1 / 0;
 //~^ WARN any use of this value will cause an error
 //~| WARN this was previously accepted by the compiler
diff --git a/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr
new file mode 100644
index 00000000000..05656afd22d
--- /dev/null
+++ b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr
@@ -0,0 +1,14 @@
+warning: any use of this value will cause an error
+  --> $DIR/allowed-deny-by-default-lint.rs:7:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: requested on the command line with `--force-warn const-err`
+   = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs
index d8447bd2382..86ab12668a3 100644
--- a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs
+++ b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs
@@ -1,3 +1,5 @@
+// --force-warn $LINT causes $LINT (which is warn-by-default) to warn
+// despite $LINT_GROUP (which contains $LINT) being allowed
 // compile-flags: --force-warn bare_trait_objects -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
index c1ebdb9514b..d945cc3347a 100644
--- a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr
+++ b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
@@ -1,5 +1,5 @@
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/force-lint-in-allowed-group.rs:8:25
+  --> $DIR/allowed-group-warn-by-default-lint.rs:10:25
    |
 LL | pub fn function(_x: Box<SomeTrait>) {}
    |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.rs b/src/test/ui/lint/force-warn/allowed-warn-by-default-lint.rs
index 280de506472..7204782a324 100644
--- a/src/test/ui/lint/force-warn/force-allowed-warning.rs
+++ b/src/test/ui/lint/force-warn/allowed-warn-by-default-lint.rs
@@ -1,3 +1,5 @@
+// --force-warn $LINT causes $LINT (which is warn-by-default) to warn
+// despite $LINT being allowed in module
 // compile-flags: --force-warn dead_code -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/allowed-warn-by-default-lint.stderr
index 3305f2c0283..c46d7403fd0 100644
--- a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr
+++ b/src/test/ui/lint/force-warn/allowed-warn-by-default-lint.stderr
@@ -1,5 +1,5 @@
 warning: function is never used: `dead_function`
-  --> $DIR/force-lint-allow-all-warnings.rs:6:4
+  --> $DIR/allowed-warn-by-default-lint.rs:8:4
    |
 LL | fn dead_function() {}
    |    ^^^^^^^^^^^^^
diff --git a/src/test/ui/lint/force-warn/force-warn-cap-lints-allow.rs b/src/test/ui/lint/force-warn/cap-lints-allow.rs
index e10d161e7c6..de3a1bd8dd7 100644
--- a/src/test/ui/lint/force-warn/force-warn-cap-lints-allow.rs
+++ b/src/test/ui/lint/force-warn/cap-lints-allow.rs
@@ -1,3 +1,5 @@
+// --force-warn $LINT casuses $LINT to warn despite --cap-lints
+// set to allow
 // compile-flags: --cap-lints allow  --force-warn bare_trait_objects -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-warn-cap-lints-allow.stderr b/src/test/ui/lint/force-warn/cap-lints-allow.stderr
index 8514956af74..f3ae16b5657 100644
--- a/src/test/ui/lint/force-warn/force-warn-cap-lints-allow.stderr
+++ b/src/test/ui/lint/force-warn/cap-lints-allow.stderr
@@ -1,5 +1,5 @@
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/force-warn-cap-lints-allow.rs:6:25
+  --> $DIR/cap-lints-allow.rs:8:25
    |
 LL | pub fn function(_x: Box<SomeTrait>) {}
    |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
diff --git a/src/test/ui/lint/force-warn/force-warn-cap-lints-warn.rs b/src/test/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.rs
index 4afc0868608..70fb90dc199 100644
--- a/src/test/ui/lint/force-warn/force-warn-cap-lints-warn.rs
+++ b/src/test/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.rs
@@ -1,3 +1,5 @@
+// --force-warn $LINT_GROUP causes $LINT to warn despite $LINT being
+// allowed in module and cap-lints set to warn
 // compile-flags: --cap-lints warn  --force-warn rust-2021-compatibility -Zunstable-options
 // check-pass
 #![allow(ellipsis_inclusive_range_patterns)]
diff --git a/src/test/ui/lint/force-warn/force-warn-cap-lints-warn.stderr b/src/test/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
index 3a0227463e6..3dafaf7055f 100644
--- a/src/test/ui/lint/force-warn/force-warn-cap-lints-warn.stderr
+++ b/src/test/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
@@ -1,5 +1,5 @@
 warning: `...` range patterns are deprecated
-  --> $DIR/force-warn-cap-lints-warn.rs:8:10
+  --> $DIR/cap-lints-warn-allowed-warn-by-default-lint.rs:10:10
    |
 LL |         0...100 => true,
    |          ^^^ help: use `..=` for an inclusive range
diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/deny-by-default-lint.rs
index d066feba869..b0a15cc2fba 100644
--- a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs
+++ b/src/test/ui/lint/force-warn/deny-by-default-lint.rs
@@ -1,7 +1,7 @@
+// --force-warn $LINT causes $LINT (which is deny-by-default) to warn
 // compile-flags: --force-warn const_err -Zunstable-options
 // check-pass
 
-#![allow(const_err)]
 const C: i32 = 1 / 0;
 //~^ WARN any use of this value will cause an error
 //~| WARN this was previously accepted by the compiler
diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/deny-by-default-lint.stderr
index 68cd3a392f5..ef295f99e64 100644
--- a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/deny-by-default-lint.stderr
@@ -1,5 +1,5 @@
 warning: any use of this value will cause an error
-  --> $DIR/force-deny-by-default-lint.rs:4:16
+  --> $DIR/deny-by-default-lint.rs:5:16
    |
 LL | const C: i32 = 1 / 0;
    | ---------------^^^^^-
diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs b/src/test/ui/lint/force-warn/lint-group-allow-warnings.rs
index aaca59a2a2a..e5dcd9a7ea1 100644
--- a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs
+++ b/src/test/ui/lint/force-warn/lint-group-allow-warnings.rs
@@ -1,3 +1,6 @@
+// --force-warn $LINT_GROUP causes $LINT in $LINT_GROUP to warn
+// despite all warnings being allowed in module
+// warn-by-default lint to warn
 // compile-flags: --force-warn nonstandard_style -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/lint-group-allow-warnings.stderr
index 065a8f6a556..dc7b1b7b98d 100644
--- a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr
+++ b/src/test/ui/lint/force-warn/lint-group-allow-warnings.stderr
@@ -1,5 +1,5 @@
 warning: function `FUNCTION` should have a snake case name
-  --> $DIR/force-lint-group-allow-all-warnings.rs:6:8
+  --> $DIR/lint-group-allow-warnings.rs:9:8
    |
 LL | pub fn FUNCTION() {}
    |        ^^^^^^^^ help: convert the identifier to snake case: `function`
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs
new file mode 100644
index 00000000000..4eb05b538b0
--- /dev/null
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs
@@ -0,0 +1,12 @@
+// --force-warn $LINT_GROUP causes $LINT (which is warn-by-default) to warn
+// despite $LINT being allowed on command line
+// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms -Zunstable-options
+// check-pass
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
new file mode 100644
index 00000000000..dc62521bf89
--- /dev/null
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
@@ -0,0 +1,12 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/lint-group-allowed-cli-warn-by-default-lint.rs:8:25
+   |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+   |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-warn-group.rs b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs
index 0198610b78e..dc13b2b2474 100644
--- a/src/test/ui/lint/force-warn/force-warn-group.rs
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs
@@ -1,3 +1,5 @@
+// --force-warn $LINT_GROUP causes $LINT to warn despite
+// $LINT_GROUP being allowed in module
 // compile-flags: --force-warn rust_2018_idioms -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-warn-group.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
index 54bee452cdd..fcbae024eb6 100644
--- a/src/test/ui/lint/force-warn/force-warn-group.stderr
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
@@ -1,5 +1,5 @@
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/force-warn-group.rs:8:25
+  --> $DIR/lint-group-allowed-lint-group.rs:10:25
    |
 LL | pub fn function(_x: Box<SomeTrait>) {}
    |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs
index 193ba2b6f0d..b7f79b3d4aa 100644
--- a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs
@@ -1,3 +1,5 @@
+// --force-warn $LINT_GROUP causes $LINT (which is warn-by-default) to warn
+// despite $LINT being allowed in module
 // compile-flags: --force-warn rust-2018-idioms -Zunstable-options
 // check-pass
 
diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
index 29eba6d635f..1212ae083c2 100644
--- a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
@@ -1,5 +1,5 @@
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/force-warn-group-allow-warning.rs:8:25
+  --> $DIR/lint-group-allowed-warn-by-default-lint.rs:10:25
    |
 LL | pub fn function(_x: Box<SomeTrait>) {}
    |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
diff --git a/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs b/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs
new file mode 100644
index 00000000000..d2cb3417be6
--- /dev/null
+++ b/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs
@@ -0,0 +1,18 @@
+// --force-warn $LINT causes $LINT (which is warn-by-default) to warn
+// despite being allowed in one submodule (but not the other)
+// compile-flags: --force-warn dead_code -Zunstable-options
+// check-pass
+
+mod one {
+    #![allow(dead_code)]
+
+    fn dead_function() {}
+    //~^ WARN function is never used
+}
+
+mod two {
+    fn dead_function() {}
+    //~^ WARN function is never used
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.stderr b/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.stderr
new file mode 100644
index 00000000000..2a3cf85a1e3
--- /dev/null
+++ b/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.stderr
@@ -0,0 +1,16 @@
+warning: function is never used: `dead_function`
+  --> $DIR/warn-by-default-lint-two-modules.rs:9:8
+   |
+LL |     fn dead_function() {}
+   |        ^^^^^^^^^^^^^
+   |
+   = note: requested on the command line with `--force-warn dead-code`
+
+warning: function is never used: `dead_function`
+  --> $DIR/warn-by-default-lint-two-modules.rs:14:8
+   |
+LL |     fn dead_function() {}
+   |        ^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/lint/force-warn/warnings-lint-group.rs b/src/test/ui/lint/force-warn/warnings-lint-group.rs
new file mode 100644
index 00000000000..fa25a1f8a84
--- /dev/null
+++ b/src/test/ui/lint/force-warn/warnings-lint-group.rs
@@ -0,0 +1,5 @@
+// --force-warn warnings is an error
+// compile-flags: --force-warn warnings -Zunstable-options
+// error-pattern: `warnings` lint group is not supported
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/warnings-lint-group.stderr b/src/test/ui/lint/force-warn/warnings-lint-group.stderr
new file mode 100644
index 00000000000..03f5788b527
--- /dev/null
+++ b/src/test/ui/lint/force-warn/warnings-lint-group.stderr
@@ -0,0 +1,9 @@
+error[E0602]: `warnings` lint group is not supported with ´--force-warn´
+
+error[E0602]: `warnings` lint group is not supported with ´--force-warn´
+
+error[E0602]: `warnings` lint group is not supported with ´--force-warn´
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0602`.
diff --git a/src/test/ui/llvm-asm/issue-69092.rs b/src/test/ui/llvm-asm/issue-69092.rs
index 26fccec80f1..ea1b80cc9b0 100644
--- a/src/test/ui/llvm-asm/issue-69092.rs
+++ b/src/test/ui/llvm-asm/issue-69092.rs
@@ -1,5 +1,7 @@
 // build-fail
 // ignore-emscripten no asm! support
+// The error message differs slightly between LLVM versions
+// min-llvm-version: 13.0
 // Regression test for #69092
 
 #![feature(llvm_asm)]
@@ -7,5 +9,5 @@
 
 fn main() {
     unsafe { llvm_asm!(".ascii \"Xen\0\""); }
-    //~^ ERROR: expected string in '.ascii' directive
+    //~^ ERROR: expected string
 }
diff --git a/src/test/ui/llvm-asm/issue-69092.stderr b/src/test/ui/llvm-asm/issue-69092.stderr
index 15a35e43c27..28c5fbbca3c 100644
--- a/src/test/ui/llvm-asm/issue-69092.stderr
+++ b/src/test/ui/llvm-asm/issue-69092.stderr
@@ -1,5 +1,5 @@
-error: expected string in '.ascii' directive
-  --> $DIR/issue-69092.rs:9:14
+error: expected string
+  --> $DIR/issue-69092.rs:11:14
    |
 LL |     unsafe { llvm_asm!(".ascii \"Xen\0\""); }
    |              ^
diff --git a/src/test/ui/macros/issue-88228.rs b/src/test/ui/macros/issue-88228.rs
new file mode 100644
index 00000000000..615b865e9f1
--- /dev/null
+++ b/src/test/ui/macros/issue-88228.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Z deduplicate-diagnostics=yes
+// edition:2018
+
+mod hey {
+    pub use Copy as Bla;
+    pub use std::println as bla;
+}
+
+#[derive(Bla)]
+//~^ ERROR cannot find derive macro `Bla`
+//~| NOTE consider importing this derive macro
+struct A;
+
+#[derive(println)]
+//~^ ERROR cannot find derive macro `println`
+struct B;
+
+fn main() {
+    bla!();
+    //~^ ERROR cannot find macro `bla`
+    //~| NOTE consider importing this macro
+}
diff --git a/src/test/ui/macros/issue-88228.stderr b/src/test/ui/macros/issue-88228.stderr
new file mode 100644
index 00000000000..b164e39064c
--- /dev/null
+++ b/src/test/ui/macros/issue-88228.stderr
@@ -0,0 +1,26 @@
+error: cannot find macro `bla` in this scope
+  --> $DIR/issue-88228.rs:19:5
+   |
+LL |     bla!();
+   |     ^^^
+   |
+   = note: consider importing this macro:
+           crate::hey::bla
+
+error: cannot find derive macro `println` in this scope
+  --> $DIR/issue-88228.rs:14:10
+   |
+LL | #[derive(println)]
+   |          ^^^^^^^
+
+error: cannot find derive macro `Bla` in this scope
+  --> $DIR/issue-88228.rs:9:10
+   |
+LL | #[derive(Bla)]
+   |          ^^^
+   |
+   = note: consider importing this derive macro:
+           crate::hey::Bla
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/macros/macro-expanded-include/test.rs b/src/test/ui/macros/macro-expanded-include/test.rs
index f1a71059a89..6a2b5ef7241 100644
--- a/src/test/ui/macros/macro-expanded-include/test.rs
+++ b/src/test/ui/macros/macro-expanded-include/test.rs
@@ -1,4 +1,4 @@
-// ignore-emscripten no llvm_asm! support
+// needs-asm-support
 // build-pass (FIXME(62277): could be check-pass?)
 #![feature(asm)]
 #![allow(unused)]
diff --git a/src/test/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs b/src/test/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs
new file mode 100644
index 00000000000..a8f3db5f5b2
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs
@@ -0,0 +1,9 @@
+// check-pass
+#![feature(marker_trait_attr)]
+
+#[marker]
+pub trait F {}
+impl<T> F for T where T: Copy {}
+impl<T> F for T where T: 'static {}
+
+fn main() {}
diff --git a/src/test/ui/marker_trait_attr/region-overlap.rs b/src/test/ui/marker_trait_attr/region-overlap.rs
new file mode 100644
index 00000000000..b3c66710355
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/region-overlap.rs
@@ -0,0 +1,8 @@
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait A {}
+impl<'a> A for (&'static (), &'a ()) {} //~ ERROR type annotations needed
+impl<'a> A for (&'a (), &'static ()) {} //~ ERROR type annotations needed
+
+fn main() {}
diff --git a/src/test/ui/marker_trait_attr/region-overlap.stderr b/src/test/ui/marker_trait_attr/region-overlap.stderr
new file mode 100644
index 00000000000..e4a94d56f12
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/region-overlap.stderr
@@ -0,0 +1,29 @@
+error[E0283]: type annotations needed
+  --> $DIR/region-overlap.rs:5:10
+   |
+LL | impl<'a> A for (&'static (), &'a ()) {}
+   |          ^ cannot infer type for tuple `(&'static (), &'a ())`
+   |
+   = note: cannot satisfy `(&'static (), &'a ()): A`
+note: required by a bound in `A`
+  --> $DIR/region-overlap.rs:4:1
+   |
+LL | trait A {}
+   | ^^^^^^^ required by this bound in `A`
+
+error[E0283]: type annotations needed
+  --> $DIR/region-overlap.rs:6:10
+   |
+LL | impl<'a> A for (&'a (), &'static ()) {}
+   |          ^ cannot infer type for tuple `(&'a (), &'static ())`
+   |
+   = note: cannot satisfy `(&'a (), &'static ()): A`
+note: required by a bound in `A`
+  --> $DIR/region-overlap.rs:4:1
+   |
+LL | trait A {}
+   | ^^^^^^^ required by this bound in `A`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/marker_trait_attr/unsound-overlap.rs b/src/test/ui/marker_trait_attr/unsound-overlap.rs
new file mode 100644
index 00000000000..2e5101b822c
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/unsound-overlap.rs
@@ -0,0 +1,25 @@
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait A {}
+
+trait B {}
+
+impl<T: A> B for T {}
+impl<T: B> A for T {}
+impl A for &str {}
+impl<T: A + B> A for (T,) {}
+trait TraitWithAssoc {
+    type Assoc;
+}
+
+impl<T: A> TraitWithAssoc for T {
+    type Assoc = T;
+}
+
+impl TraitWithAssoc for ((&str,),) {
+    //~^ ERROR conflicting implementations
+    type Assoc = ((&'static str,),);
+}
+
+fn main() {}
diff --git a/src/test/ui/marker_trait_attr/unsound-overlap.stderr b/src/test/ui/marker_trait_attr/unsound-overlap.stderr
new file mode 100644
index 00000000000..5ebac8270dd
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/unsound-overlap.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `TraitWithAssoc` for type `((&str,),)`
+  --> $DIR/unsound-overlap.rs:20:1
+   |
+LL | impl<T: A> TraitWithAssoc for T {
+   | ------------------------------- first implementation here
+...
+LL | impl TraitWithAssoc for ((&str,),) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `((&str,),)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
index 4115fec86fb..3b160935a2f 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
@@ -16,6 +16,8 @@ error: cannot find attribute `empty_helper` in this scope
 LL |             #[derive(GenHelperUse)]
    |                      ^^^^^^^^^^^^
    |
+   = note: consider importing this attribute macro:
+           empty_helper
    = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: cannot find attribute `empty_helper` in this scope
@@ -27,6 +29,8 @@ LL |         #[empty_helper]
 LL |             gen_helper_use!();
    |             ------------------ in this macro invocation
    |
+   = note: consider importing this attribute macro:
+           crate::empty_helper
    = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
index 7f197a238e5..be55890c08c 100644
--- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
+++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
@@ -1,7 +1,7 @@
-error[E0391]: cycle detected when computing layout of `S`
+error[E0391]: cycle detected when computing layout of `std::option::Option<S>`
    |
-   = note: ...which requires computing layout of `std::option::Option<S>`...
-   = note: ...which again requires computing layout of `S`, completing the cycle
+   = note: ...which requires computing layout of `S`...
+   = note: ...which again requires computing layout of `std::option::Option<S>`, completing the cycle
 note: cycle used when optimizing MIR for `main`
   --> $DIR/issue-26548-recursion-via-normalize.rs:15:1
    |
diff --git a/src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs b/src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
new file mode 100644
index 00000000000..8d0a9ef0ace
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
@@ -0,0 +1,39 @@
+// run-pass
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo<T: Default + ToString>: Bar<i32> + Bar<T> {}
+trait Bar<T: Default + ToString> {
+    fn bar(&self) -> String {
+        T::default().to_string()
+    }
+}
+
+struct S1;
+
+impl Bar<i32> for S1 {}
+impl Foo<i32> for S1 {}
+
+struct S2;
+impl Bar<i32> for S2 {}
+impl Bar<bool> for S2 {}
+impl Foo<bool> for S2 {}
+
+fn test1(x: &dyn Foo<i32>) {
+    let s = x as &dyn Bar<i32>;
+    assert_eq!("0", &s.bar().to_string());
+}
+
+fn test2(x: &dyn Foo<bool>) {
+    let p = x as &dyn Bar<i32>;
+    assert_eq!("0", &p.bar().to_string());
+    let q = x as &dyn Bar<bool>;
+    assert_eq!("false", &q.bar().to_string());
+}
+
+fn main() {
+    let s1 = S1;
+    test1(&s1);
+    let s2 = S2;
+    test2(&s2);
+}
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
index 1a0e5072843..79ddedd4187 100644
--- a/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
@@ -9,12 +9,8 @@ trait Bar<T> {
 }
 
 fn test_specific(x: &dyn Foo) {
-    let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
-                                //~^ ERROR non-primitive cast
-                                //~^^ ERROR the trait bound `&dyn Foo: Bar<i32>` is not satisfied
-    let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
-                                //~^ ERROR non-primitive cast
-                                //~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
+    let _ = x as &dyn Bar<i32>; // OK
+    let _ = x as &dyn Bar<u32>; // OK
 }
 
 fn test_unknown_version(x: &dyn Foo) {
@@ -24,9 +20,7 @@ fn test_unknown_version(x: &dyn Foo) {
 }
 
 fn test_infer_version(x: &dyn Foo) {
-    let a = x as &dyn Bar<_>; // FIXME: OK, eventually
-                              //~^ ERROR non-primitive cast
-                              //~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
+    let a = x as &dyn Bar<_>; // OK
     let _: Option<u32> = a.bar();
 }
 
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr
index da647f16c3d..44f32e0cec9 100644
--- a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr
@@ -1,43 +1,5 @@
-error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<i32>`
-  --> $DIR/type-checking-test-1.rs:12:13
-   |
-LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
-   |             ^^^^^^^^^^^^^^^^^^ invalid cast
-   |
-help: consider borrowing the value
-   |
-LL |     let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
-   |             +
-
-error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
-  --> $DIR/type-checking-test-1.rs:15:13
-   |
-LL |     let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
-   |             ^^^^^^^^^^^^^^^^^^ invalid cast
-   |
-help: consider borrowing the value
-   |
-LL |     let _ = &x as &dyn Bar<u32>; // FIXME: OK, eventually
-   |             +
-
-error[E0277]: the trait bound `&dyn Foo: Bar<i32>` is not satisfied
-  --> $DIR/type-checking-test-1.rs:12:13
-   |
-LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
-   |             ^ the trait `Bar<i32>` is not implemented for `&dyn Foo`
-   |
-   = note: required for the cast to the object type `dyn Bar<i32>`
-
-error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
-  --> $DIR/type-checking-test-1.rs:15:13
-   |
-LL |     let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
-   |             ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
-   |
-   = note: required for the cast to the object type `dyn Bar<u32>`
-
 error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-1.rs:21:13
+  --> $DIR/type-checking-test-1.rs:17:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ invalid cast
@@ -48,33 +10,14 @@ LL |     let _ = &x as &dyn Bar<_>; // Ambiguous
    |             +
 
 error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied
-  --> $DIR/type-checking-test-1.rs:21:13
+  --> $DIR/type-checking-test-1.rs:17:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^ the trait `Bar<_>` is not implemented for `&dyn Foo`
    |
    = note: required for the cast to the object type `dyn Bar<_>`
 
-error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
-  --> $DIR/type-checking-test-1.rs:27:13
-   |
-LL |     let a = x as &dyn Bar<_>; // FIXME: OK, eventually
-   |             ^^^^^^^^^^^^^^^^ invalid cast
-   |
-help: consider borrowing the value
-   |
-LL |     let a = &x as &dyn Bar<_>; // FIXME: OK, eventually
-   |             +
-
-error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
-  --> $DIR/type-checking-test-1.rs:27:13
-   |
-LL |     let a = x as &dyn Bar<_>; // FIXME: OK, eventually
-   |             ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
-   |
-   = note: required for the cast to the object type `dyn Bar<u32>`
-
-error: aborting due to 8 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0605.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
index 326df74211e..32754c53803 100644
--- a/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
@@ -13,9 +13,7 @@ fn test_specific(x: &dyn Foo<i32>) {
 }
 
 fn test_specific2(x: &dyn Foo<u32>) {
-    let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
-                                //~^ ERROR non-primitive cast
-                                //~^^ ERROR the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
+    let _ = x as &dyn Bar<i32>; // OK
 }
 
 fn test_specific3(x: &dyn Foo<i32>) {
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr
index 582eddc7aa0..4ae4c8552c1 100644
--- a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr
@@ -1,24 +1,5 @@
-error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<i32>`
-  --> $DIR/type-checking-test-2.rs:16:13
-   |
-LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
-   |             ^^^^^^^^^^^^^^^^^^ invalid cast
-   |
-help: consider borrowing the value
-   |
-LL |     let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
-   |             +
-
-error[E0277]: the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
-  --> $DIR/type-checking-test-2.rs:16:13
-   |
-LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
-   |             ^ the trait `Bar<i32>` is not implemented for `&dyn Foo<u32>`
-   |
-   = note: required for the cast to the object type `dyn Bar<i32>`
-
 error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
-  --> $DIR/type-checking-test-2.rs:22:13
+  --> $DIR/type-checking-test-2.rs:20:13
    |
 LL |     let _ = x as &dyn Bar<u32>; // Error
    |             ^^^^^^^^^^^^^^^^^^ invalid cast
@@ -29,7 +10,7 @@ LL |     let _ = &x as &dyn Bar<u32>; // Error
    |             +
 
 error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
-  --> $DIR/type-checking-test-2.rs:22:13
+  --> $DIR/type-checking-test-2.rs:20:13
    |
 LL |     let _ = x as &dyn Bar<u32>; // Error
    |             ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>`
@@ -37,7 +18,7 @@ LL |     let _ = x as &dyn Bar<u32>; // Error
    = note: required for the cast to the object type `dyn Bar<u32>`
 
 error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-2.rs:28:13
+  --> $DIR/type-checking-test-2.rs:26:13
    |
 LL |     let a = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ invalid cast
@@ -48,14 +29,14 @@ LL |     let a = &x as &dyn Bar<_>; // Ambiguous
    |             +
 
 error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
-  --> $DIR/type-checking-test-2.rs:28:13
+  --> $DIR/type-checking-test-2.rs:26:13
    |
 LL |     let a = x as &dyn Bar<_>; // Ambiguous
    |             ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>`
    |
    = note: required for the cast to the object type `dyn Bar<_>`
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0277, E0605.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/defining-use-submodule.rs b/src/test/ui/type-alias-impl-trait/defining-use-submodule.rs
new file mode 100644
index 00000000000..8b51f55715e
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/defining-use-submodule.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+// test that the type alias impl trait defining use is in a submodule
+
+fn main() {}
+
+type Foo = impl std::fmt::Display;
+type Bar = impl std::fmt::Display;
+
+mod foo {
+    pub fn foo() -> super::Foo {
+        "foo"
+    }
+
+    pub mod bar {
+        pub fn bar() -> crate::Bar {
+            1
+        }
+    }
+}
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs
index 766ee36c02b..d87a25aad58 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs
@@ -3,8 +3,7 @@
 fn main() {}
 
 trait Trait {}
-type Underconstrained<T: Trait> = impl 'static;
-//~^ ERROR: at least one trait must be specified
+type Underconstrained<T: Trait> = impl Send;
 
 // no `Trait` bound
 fn underconstrain<T>(_: T) -> Underconstrained<T> {
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
index 99eb884a0e8..c73288329b0 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
@@ -1,11 +1,5 @@
-error: at least one trait must be specified
-  --> $DIR/generic_underconstrained.rs:6:35
-   |
-LL | type Underconstrained<T: Trait> = impl 'static;
-   |                                   ^^^^^^^^^^^^
-
 error[E0277]: the trait bound `T: Trait` is not satisfied
-  --> $DIR/generic_underconstrained.rs:10:31
+  --> $DIR/generic_underconstrained.rs:9:31
    |
 LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
    |                               ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
@@ -13,13 +7,13 @@ LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
 note: required by a bound in `Underconstrained`
   --> $DIR/generic_underconstrained.rs:6:26
    |
-LL | type Underconstrained<T: Trait> = impl 'static;
+LL | type Underconstrained<T: Trait> = impl Send;
    |                          ^^^^^ required by this bound in `Underconstrained`
 help: consider restricting type parameter `T`
    |
 LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {
    |                    +++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs
index cd7c962e2d1..8adc0bf32a6 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs
@@ -2,8 +2,7 @@
 
 fn main() {}
 
-type Underconstrained<T: std::fmt::Debug> = impl 'static;
-//~^ ERROR: at least one trait must be specified
+type Underconstrained<T: std::fmt::Debug> = impl Send;
 
 // not a defining use, because it doesn't define *all* possible generics
 fn underconstrained<U>(_: U) -> Underconstrained<U> {
@@ -11,8 +10,7 @@ fn underconstrained<U>(_: U) -> Underconstrained<U> {
     5u32
 }
 
-type Underconstrained2<T: std::fmt::Debug> = impl 'static;
-//~^ ERROR: at least one trait must be specified
+type Underconstrained2<T: std::fmt::Debug> = impl Send;
 
 // not a defining use, because it doesn't define *all* possible generics
 fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index 1c1193705f9..d77d978aa44 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -1,17 +1,5 @@
-error: at least one trait must be specified
-  --> $DIR/generic_underconstrained2.rs:5:45
-   |
-LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
-   |                                             ^^^^^^^^^^^^
-
-error: at least one trait must be specified
-  --> $DIR/generic_underconstrained2.rs:14:46
-   |
-LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
-   |                                              ^^^^^^^^^^^^
-
 error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:9:33
+  --> $DIR/generic_underconstrained2.rs:8:33
    |
 LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
    |                                 ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
@@ -19,7 +7,7 @@ LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
 note: required by a bound in `Underconstrained`
   --> $DIR/generic_underconstrained2.rs:5:26
    |
-LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
+LL | type Underconstrained<T: std::fmt::Debug> = impl Send;
    |                          ^^^^^^^^^^^^^^^ required by this bound in `Underconstrained`
 help: consider restricting type parameter `U`
    |
@@ -27,21 +15,21 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
    |                      +++++++++++++++++
 
 error[E0277]: `V` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:18:43
+  --> $DIR/generic_underconstrained2.rs:16:43
    |
 LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
    |                                           ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
 note: required by a bound in `Underconstrained2`
-  --> $DIR/generic_underconstrained2.rs:14:27
+  --> $DIR/generic_underconstrained2.rs:13:27
    |
-LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
+LL | type Underconstrained2<T: std::fmt::Debug> = impl Send;
    |                           ^^^^^^^^^^^^^^^ required by this bound in `Underconstrained2`
 help: consider restricting type parameter `V`
    |
 LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> {
    |                          +++++++++++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/incomplete-inference.rs b/src/test/ui/type-alias-impl-trait/incomplete-inference.rs
new file mode 100644
index 00000000000..955d1288a45
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/incomplete-inference.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl Sized;
+
+fn bar() -> Foo {
+    None
+    //~^ ERROR: type annotations needed [E0282]
+}
+
+fn baz() -> Foo {
+    //~^ ERROR: concrete type differs from previous defining opaque type use
+    Some(())
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr b/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr
new file mode 100644
index 00000000000..53cdf9e5b38
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr
@@ -0,0 +1,21 @@
+error[E0282]: type annotations needed
+  --> $DIR/incomplete-inference.rs:6:5
+   |
+LL |     None
+   |     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/incomplete-inference.rs:10:1
+   |
+LL | fn baz() -> Foo {
+   | ^^^^^^^^^^^^^^^ expected `[type error]`, got `Option<()>`
+   |
+note: previous use here
+  --> $DIR/incomplete-inference.rs:5:1
+   |
+LL | fn bar() -> Foo {
+   | ^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-dyn.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-dyn.rs
new file mode 100644
index 00000000000..f6a83029670
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-dyn.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+type Foo = Box<dyn Iterator<Item = impl Send>>;
+
+fn make_foo() -> Foo {
+    Box::new(vec![1, 2, 3].into_iter())
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-impl-trait.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-impl-trait.rs
new file mode 100644
index 00000000000..fddecfcacf6
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-assoc-impl-trait.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+type Foo = impl Iterator<Item = impl Send>;
+
+fn make_foo() -> Foo {
+    vec![1, 2].into_iter()
+}
+
+type Bar = impl Send;
+type Baz = impl Iterator<Item = Bar>;
+
+fn make_baz() -> Baz {
+    vec!["1", "2"].into_iter()
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs
new file mode 100644
index 00000000000..299bdf562dc
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs
@@ -0,0 +1,13 @@
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+// FIXME: this is ruled out for now but should work
+
+type Foo = fn() -> impl Send;
+//~^ ERROR: `impl Trait` not allowed outside of function and method return types
+
+fn make_foo() -> Foo {
+    || 15
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr
new file mode 100644
index 00000000000..1c5d57d4af7
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr
@@ -0,0 +1,9 @@
+error[E0562]: `impl Trait` not allowed outside of function and method return types
+  --> $DIR/type-alias-impl-trait-fn-type.rs:6:20
+   |
+LL | type Foo = fn() -> impl Send;
+   |                    ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-struct.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-struct.rs
new file mode 100644
index 00000000000..1a4064055db
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-struct.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+type Foo = Vec<impl Send>;
+
+fn make_foo() -> Foo {
+    vec![true, false]
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-tuple.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-tuple.rs
index 86c9d482143..1f2d0e47ea3 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-tuple.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-tuple.rs
@@ -7,20 +7,19 @@ pub trait MyTrait {}
 
 impl MyTrait for bool {}
 
+type Foo = impl MyTrait;
+
 struct Blah {
     my_foo: Foo,
-    my_u8: u8
+    my_u8: u8,
 }
 
 impl Blah {
     fn new() -> Blah {
-        Blah {
-            my_foo: make_foo(),
-            my_u8: 12
-        }
+        Blah { my_foo: make_foo(), my_u8: 12 }
     }
-    fn into_inner(self) -> (Foo, u8) {
-        (self.my_foo, self.my_u8)
+    fn into_inner(self) -> (Foo, u8, Foo) {
+        (self.my_foo, self.my_u8, make_foo())
     }
 }
 
@@ -28,6 +27,4 @@ fn make_foo() -> Foo {
     true
 }
 
-type Foo = impl MyTrait;
-
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
index 80192d19af9..d2c8c1f63df 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
@@ -11,7 +11,6 @@ fn main() {
     assert_eq!(bar2().to_string(), "bar2");
     let mut x = bar1();
     x = bar2();
-    assert_eq!(boo::boo().to_string(), "boo");
     assert_eq!(my_iter(42u8).collect::<Vec<u8>>(), vec![42u8]);
 }
 
@@ -33,15 +32,6 @@ fn bar2() -> Bar {
     "bar2"
 }
 
-// definition in submodule
-type Boo = impl std::fmt::Display;
-
-mod boo {
-    pub fn boo() -> super::Boo {
-        "boo"
-    }
-}
-
 type MyIter<T> = impl Iterator<Item = T>;
 
 fn my_iter<T>(t: T) -> MyIter<T> {
diff --git a/src/test/ui/type-alias-impl-trait/unused_generic_param.rs b/src/test/ui/type-alias-impl-trait/unused_generic_param.rs
index 04a5c58cd36..ad5e4918cca 100644
--- a/src/test/ui/type-alias-impl-trait/unused_generic_param.rs
+++ b/src/test/ui/type-alias-impl-trait/unused_generic_param.rs
@@ -1,16 +1,17 @@
+// check-pass
+
 #![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
 
 fn main() {}
 
-type PartiallyDefined<T> = impl 'static;
-//~^ ERROR: at least one trait must be specified
+type PartiallyDefined<T> = impl Sized;
 
 fn partially_defined<T: std::fmt::Debug>(_: T) -> PartiallyDefined<T> {
     4u32
 }
 
-type PartiallyDefined2<T> = impl 'static;
-//~^ ERROR: at least one trait must be specified
+type PartiallyDefined2<T> = impl Sized;
 
 fn partially_defined2<T: std::fmt::Debug>(_: T) -> PartiallyDefined2<T> {
     4u32
diff --git a/src/test/ui/type-alias-impl-trait/unused_generic_param.stderr b/src/test/ui/type-alias-impl-trait/unused_generic_param.stderr
deleted file mode 100644
index 4e11854b071..00000000000
--- a/src/test/ui/type-alias-impl-trait/unused_generic_param.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: at least one trait must be specified
-  --> $DIR/unused_generic_param.rs:5:28
-   |
-LL | type PartiallyDefined<T> = impl 'static;
-   |                            ^^^^^^^^^^^^
-
-error: at least one trait must be specified
-  --> $DIR/unused_generic_param.rs:12:29
-   |
-LL | type PartiallyDefined2<T> = impl 'static;
-   |                             ^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/typeck/issue-87935-unsized-box-expr.rs b/src/test/ui/typeck/issue-87935-unsized-box-expr.rs
new file mode 100644
index 00000000000..cd2a82074ed
--- /dev/null
+++ b/src/test/ui/typeck/issue-87935-unsized-box-expr.rs
@@ -0,0 +1,10 @@
+#![feature(box_syntax)]
+// Box expression needs to be movable, and hence has to be of a Sized type.
+fn main() {
+    let _x: Box<[u32]> = box { loop {} };
+    //~^ ERROR: the size for values of type `[u32]` cannot be known at compilation time
+
+    // Check that a deduced size does not cause issues.
+    let _y: Box<[u32]> = box [];
+    let _z: Box<[u32; 0]> = box { loop {} };
+}
diff --git a/src/test/ui/typeck/issue-87935-unsized-box-expr.stderr b/src/test/ui/typeck/issue-87935-unsized-box-expr.stderr
new file mode 100644
index 00000000000..9ff822352a1
--- /dev/null
+++ b/src/test/ui/typeck/issue-87935-unsized-box-expr.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the size for values of type `[u32]` cannot be known at compilation time
+  --> $DIR/issue-87935-unsized-box-expr.rs:4:30
+   |
+LL |     let _x: Box<[u32]> = box { loop {} };
+   |                              ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u32]`
+   = note: the type of a box expression must have a statically known size
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unsafe/inline_asm.mir.stderr b/src/test/ui/unsafe/inline_asm.mir.stderr
index 7dc62a1ead1..5d9828b5594 100644
--- a/src/test/ui/unsafe/inline_asm.mir.stderr
+++ b/src/test/ui/unsafe/inline_asm.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:9:5
+  --> $DIR/inline_asm.rs:10:5
    |
 LL |     asm!("nop");
    |     ^^^^^^^^^^^^ use of inline assembly
@@ -7,7 +7,7 @@ LL |     asm!("nop");
    = note: inline assembly is entirely unchecked and can cause undefined behavior
 
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:10:5
+  --> $DIR/inline_asm.rs:11:5
    |
 LL |     llvm_asm!("nop");
    |     ^^^^^^^^^^^^^^^^^ use of inline assembly
diff --git a/src/test/ui/unsafe/inline_asm.rs b/src/test/ui/unsafe/inline_asm.rs
index 995292a9903..8e1325bc0a8 100644
--- a/src/test/ui/unsafe/inline_asm.rs
+++ b/src/test/ui/unsafe/inline_asm.rs
@@ -1,5 +1,6 @@
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
+// needs-asm-support
 
 #![feature(llvm_asm)]
 #![feature(asm)]
diff --git a/src/test/ui/unsafe/inline_asm.thir.stderr b/src/test/ui/unsafe/inline_asm.thir.stderr
index 7dc62a1ead1..5d9828b5594 100644
--- a/src/test/ui/unsafe/inline_asm.thir.stderr
+++ b/src/test/ui/unsafe/inline_asm.thir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:9:5
+  --> $DIR/inline_asm.rs:10:5
    |
 LL |     asm!("nop");
    |     ^^^^^^^^^^^^ use of inline assembly
@@ -7,7 +7,7 @@ LL |     asm!("nop");
    = note: inline assembly is entirely unchecked and can cause undefined behavior
 
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:10:5
+  --> $DIR/inline_asm.rs:11:5
    |
 LL |     llvm_asm!("nop");
    |     ^^^^^^^^^^^^^^^^^ use of inline assembly
diff --git a/src/tools/cherry-pick.sh b/src/tools/cherry-pick.sh
new file mode 100755
index 00000000000..90539a96389
--- /dev/null
+++ b/src/tools/cherry-pick.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+set -euo pipefail
+IFS=$'\n\t'
+
+print_error() {
+  echo "Error: \`$1\` is not a valid commit. To debug, run:"
+  echo
+  echo "    git rev-parse --verify $1"
+  echo
+}
+
+full_sha() {
+  git rev-parse \
+    --verify \
+    --quiet \
+    "$1^{object}" || print_error $1
+}
+
+commit_message_with_backport_note() {
+  message=$(git log --format=%B -n 1 $1)
+  echo $message | awk "NR==1{print; print \"\n(backport-of: $1)\"} NR!=1"
+}
+
+cherry_pick_commit() {
+  sha=$(full_sha $1)
+  git cherry-pick $sha > /dev/null
+  git commit \
+    --amend \
+    --file <(commit_message_with_backport_note $sha)
+}
+
+for arg ; do
+  cherry_pick_commit $arg
+done
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
index 6b63c2cf157..a42eee53459 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::visitors::LocalUsedVisitor;
-use clippy_utils::{higher, is_lang_ctor, path_to_local, peel_ref_operators, SpanlessEq};
+use clippy_utils::{higher, is_lang_ctor, is_unit_expr, path_to_local, peel_ref_operators, SpanlessEq};
 use if_chain::if_chain;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, MatchSource, Pat, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{MultiSpan, Span};
@@ -49,104 +49,87 @@ declare_lint_pass!(CollapsibleMatch => [COLLAPSIBLE_MATCH]);
 
 impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-        if let Some(higher::IfLet {
-            let_pat,
-            if_then,
-            if_else,
-            ..
-        }) = higher::IfLet::hir(expr)
-        {
-            check_arm(cx, if_then, None, let_pat, if_else);
-
-            check_if_let(cx, if_then, let_pat);
-        }
-
-        if let ExprKind::Match(_expr, arms, _source) = expr.kind {
-            if let Some(wild_arm) = arms.iter().rfind(|arm| is_wild_like(cx, &arm.pat.kind, &arm.guard)) {
-                for arm in arms {
-                    check_arm(cx, arm.body, arm.guard.as_ref(), arm.pat, Some(wild_arm.body));
+        match IfLetOrMatch::parse(cx, expr) {
+            Some(IfLetOrMatch::Match(_, arms, _)) => {
+                if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) {
+                    for arm in arms {
+                        check_arm(cx, true, arm.pat, arm.body, arm.guard.as_ref(), Some(els_arm.body));
+                    }
                 }
             }
-
-            if let Some(first_arm) = arms.get(0) {
-                check_if_let(cx, &first_arm.body, &first_arm.pat);
+            Some(IfLetOrMatch::IfLet(_, pat, body, els)) => {
+                check_arm(cx, false, pat, body, None, els);
             }
+            None => {}
         }
     }
 }
 
 fn check_arm<'tcx>(
     cx: &LateContext<'tcx>,
-    outer_block: &'tcx Expr<'tcx>,
-    outer_guard: Option<&Guard<'tcx>>,
+    outer_is_match: bool,
     outer_pat: &'tcx Pat<'tcx>,
-    wild_outer_block: Option<&'tcx Expr<'tcx>>,
+    outer_then_body: &'tcx Expr<'tcx>,
+    outer_guard: Option<&'tcx Guard<'tcx>>,
+    outer_else_body: Option<&'tcx Expr<'tcx>>
 ) {
-    let expr = strip_singleton_blocks(outer_block);
+    let inner_expr = strip_singleton_blocks(outer_then_body);
     if_chain! {
-        if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind;
-        // the outer arm pattern and the inner match
-        if expr_in.span.ctxt() == outer_pat.span.ctxt();
-        // there must be no more than two arms in the inner match for this lint
-        if arms_inner.len() == 2;
-        // no if guards on the inner match
-        if arms_inner.iter().all(|arm| arm.guard.is_none());
+        if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr);
+        if let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
+            IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)),
+            IfLetOrMatch::Match(scrutinee, arms, ..) => if_chain! {
+                // if there are more than two arms, collapsing would be non-trivial
+                if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none());
+                // one of the arms must be "wild-like"
+                if let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a));
+                then {
+                    let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
+                    Some((scrutinee, then.pat, Some(els.body)))
+                } else {
+                    None
+                }
+            },
+        };
+        if outer_pat.span.ctxt() == inner_scrutinee.span.ctxt();
         // match expression must be a local binding
         // match <local> { .. }
-        if let Some(binding_id) = path_to_local(peel_ref_operators(cx, expr_in));
-        // one of the branches must be "wild-like"
-        if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| is_wild_like(cx, &arm_inner.pat.kind, &arm_inner.guard));
-        let (wild_inner_arm, non_wild_inner_arm) =
-            (&arms_inner[wild_inner_arm_idx], &arms_inner[1 - wild_inner_arm_idx]);
-        if !pat_contains_or(non_wild_inner_arm.pat);
+        if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee));
+        if !pat_contains_or(inner_then_pat);
         // the binding must come from the pattern of the containing match arm
         // ..<local>.. => match <local> { .. }
         if let Some(binding_span) = find_pat_binding(outer_pat, binding_id);
-        // the "wild-like" branches must be equal
-        if wild_outer_block.map(|el| SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, el)).unwrap_or(true);
+        // the "else" branches must be equal
+        if match (outer_else_body, inner_else_body) {
+            (None, None) => true,
+            (None, Some(e)) | (Some(e), None) => is_unit_expr(e),
+            (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
+        };
         // the binding must not be used in the if guard
         let mut used_visitor = LocalUsedVisitor::new(cx, binding_id);
-        if match outer_guard {
-            None => true,
-            Some(Guard::If(expr) | Guard::IfLet(_, expr)) => !used_visitor.check_expr(expr),
+        if outer_guard.map_or(true, |(Guard::If(e) | Guard::IfLet(_, e))| !used_visitor.check_expr(e));
+        // ...or anywhere in the inner expression
+        if match inner {
+            IfLetOrMatch::IfLet(_, _, body, els) => {
+                !used_visitor.check_expr(body) && els.map_or(true, |e| !used_visitor.check_expr(e))
+            },
+            IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| used_visitor.check_arm(arm)),
         };
-        // ...or anywhere in the inner match
-        if !arms_inner.iter().any(|arm| used_visitor.check_arm(arm));
         then {
-            span_lint_and_then(
-                cx,
-                COLLAPSIBLE_MATCH,
-                expr.span,
-                "unnecessary nested match",
-                |diag| {
-                    let mut help_span = MultiSpan::from_spans(vec![binding_span, non_wild_inner_arm.pat.span]);
-                    help_span.push_span_label(binding_span, "replace this binding".into());
-                    help_span.push_span_label(non_wild_inner_arm.pat.span, "with this pattern".into());
-                    diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
-                },
+            let msg = format!(
+                "this `{}` can be collapsed into the outer `{}`",
+                if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" },
+                if outer_is_match { "match" } else { "if let" },
             );
-        }
-    }
-}
-
-fn check_if_let<'tcx>(cx: &LateContext<'tcx>, outer_expr: &'tcx Expr<'tcx>, outer_pat: &'tcx Pat<'tcx>) {
-    let block_inner = strip_singleton_blocks(outer_expr);
-    if_chain! {
-        if let Some(higher::IfLet { if_then: inner_if_then, let_expr: inner_let_expr, let_pat: inner_let_pat, .. }) = higher::IfLet::hir(block_inner);
-        if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_let_expr));
-        if let Some(binding_span) = find_pat_binding(outer_pat, binding_id);
-        let mut used_visitor = LocalUsedVisitor::new(cx, binding_id);
-        if !used_visitor.check_expr(inner_if_then);
-        then {
             span_lint_and_then(
                 cx,
                 COLLAPSIBLE_MATCH,
-                block_inner.span,
-                "unnecessary nested `if let` or `match`",
+                inner_expr.span,
+                &msg,
                 |diag| {
-                    let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_let_pat.span]);
+                    let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
                     help_span.push_span_label(binding_span, "replace this binding".into());
-                    help_span.push_span_label(inner_let_pat.span, "with this pattern".into());
+                    help_span.push_span_label(inner_then_pat.span, "with this pattern".into());
                     diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
                 },
             );
@@ -168,14 +151,30 @@ fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir>
     expr
 }
 
-/// A "wild-like" pattern is wild ("_") or `None`.
-/// For this lint to apply, both the outer and inner patterns
-/// must have "wild-like" branches that can be combined.
-fn is_wild_like(cx: &LateContext<'_>, pat_kind: &PatKind<'_>, arm_guard: &Option<Guard<'_>>) -> bool {
-    if arm_guard.is_some() {
+enum IfLetOrMatch<'hir> {
+    Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
+    /// scrutinee, pattern, then block, else block
+    IfLet(&'hir Expr<'hir>, &'hir Pat<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>),
+}
+
+impl<'hir> IfLetOrMatch<'hir> {
+    fn parse(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
+        match expr.kind {
+            ExprKind::Match(expr, arms, source) => Some(Self::Match(expr, arms, source)),
+            _ => higher::IfLet::hir(cx, expr).map(|higher::IfLet { let_expr, let_pat, if_then, if_else }| {
+                Self::IfLet(let_expr, let_pat, if_then, if_else)
+            })
+        }
+    }
+}
+
+/// A "wild-like" arm has a wild (`_`) or `None` pattern and no guard. Such arms can be "collapsed"
+/// into a single wild arm without any significant loss in semantics or readability.
+fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    if arm.guard.is_some() {
         return false;
     }
-    match pat_kind {
+    match arm.pat.kind {
         PatKind::Binding(..) | PatKind::Wild => true,
         PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
         _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index e2d3905eacb..7dad1c31150 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
             if_then,
             if_else: Some(if_else),
             ..
-        }) = higher::IfLet::hir(expr)
+        }) = higher::IfLet::hir(cx, expr)
         {
             op_visit.visit_expr(let_expr);
             if op_visit.mutex_lock_called {
diff --git a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
index cd813c639db..fb5637fcec1 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
@@ -45,7 +45,7 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
 impl<'tcx> LateLintPass<'tcx> for OkIfLet {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! { //begin checking variables
-            if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(expr);
+            if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr);
             if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
             if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _)  = let_pat.kind; //get operation
             if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 9f2bc3c7eba..5852674da57 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
 
         if_chain! {
             if let Some(inner_expr) = inner_expr;
-            if let Some(higher::IfLet { let_pat, let_expr, if_else: None, .. }) = higher::IfLet::hir(inner_expr);
+            if let Some(higher::IfLet { let_pat, let_expr, if_else: None, .. }) = higher::IfLet::hir(cx, inner_expr);
             // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
             if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
             if path_to_local_id(let_expr, pat_hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index 6be410ca8e3..d6d3315e0a8 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'
             let_expr,
             if_else: Some(if_else),
             ..
-        }) = higher::IfLet::hir(inner)
+        }) = higher::IfLet::hir(cx, inner)
         {
             if is_simple_break_expr(if_else) {
                 could_be_while_let(cx, expr, let_pat, let_expr);
diff --git a/src/tools/clippy/clippy_lints/src/manual_map.rs b/src/tools/clippy/clippy_lints/src/manual_map.rs
index 53d97f77543..161d8841490 100644
--- a/src/tools/clippy/clippy_lints/src/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_map.rs
@@ -49,7 +49,7 @@ impl LateLintPass<'_> for ManualMap {
             let_expr,
             if_then,
             if_else: Some(if_else),
-        }) = higher::IfLet::hir(expr)
+        }) = higher::IfLet::hir(cx, expr)
         {
             manage_lint(cx, expr, (&let_pat.kind, if_then), (&PatKind::Wild, if_else), let_expr);
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index a183d0c66e8..3d0da472ddc 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -8,9 +8,9 @@ use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
 use clippy_utils::visitors::LocalUsedVisitor;
 use clippy_utils::{
-    get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_wild, meets_msrv, msrvs,
-    path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks,
-    strip_pat_refs,
+    get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild,
+    meets_msrv, msrvs, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
+    remove_blocks, strip_pat_refs,
 };
 use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
 use core::array;
@@ -634,7 +634,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         if let ExprKind::Match(ref ex, ref arms, _) = expr.kind {
             check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
         }
-        if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(expr) {
+        if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
             check_match_ref_pats(cx, let_expr, once(let_pat), expr);
         }
     }
@@ -1298,7 +1298,7 @@ fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
         let_expr,
         if_then,
         if_else: Some(if_else),
-    }) = higher::IfLet::hir(expr)
+    }) = higher::IfLet::hir(cx, expr)
     {
         return find_matches_sugg(
             cx,
@@ -1672,14 +1672,6 @@ fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
         .collect()
 }
 
-fn is_unit_expr(expr: &Expr<'_>) -> bool {
-    match expr.kind {
-        ExprKind::Tup(v) if v.is_empty() => true,
-        ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none() => true,
-        _ => false,
-    }
-}
-
 // Checks if arm has the form `None => None`
 fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
@@ -1835,7 +1827,7 @@ mod redundant_pattern_match {
             let_pat,
             let_expr,
             ..
-        }) = higher::IfLet::ast(cx, expr)
+        }) = higher::IfLet::hir(cx, expr)
         {
             find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some())
         }
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index d0b0bad5eb1..eff3d3abff8 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -125,7 +125,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
 fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurence> {
     if_chain! {
         if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
-        if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(expr);
+        if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(cx, expr);
         if !is_else_clause(cx.tcx, expr);
         if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already
         if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind;
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 91085c13ac4..7b6a0894e6d 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -97,7 +97,7 @@ impl QuestionMark {
 
     fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
-            if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(expr);
+            if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(cx, expr);
             if Self::is_option(cx, let_expr);
 
             if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind;
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index ee675838c4c..db0f412f2a1 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -127,7 +127,7 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
                 then {
                     let data = stmt.span.data();
                     // Make a span out of the semicolon for the help message
-                    Some((span, Some(Span::new(data.hi-BytePos(1), data.hi, data.ctxt))))
+                    Some((span, Some(data.with_lo(data.hi-BytePos(1)))))
                 } else {
                     Some((span, None))
                 }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 4553ac704a2..85d1f65c51f 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -299,7 +299,7 @@ impl EarlyLintPass for Write {
                     let nl_span = match (dest, only_nl) {
                         // Special case of `write!(buf, "\n")`: Mark everything from the end of
                         // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains.
-                        (Some(dest_expr), true) => Span::new(dest_expr.span.hi(), nl_span.hi(), nl_span.ctxt()),
+                        (Some(dest_expr), true) => nl_span.with_lo(dest_expr.span.hi()),
                         _ => nl_span,
                     };
                     span_lint_and_then(
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 29b698e56e3..957ec35be6f 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -79,15 +79,7 @@ pub struct IfLet<'hir> {
 }
 
 impl<'hir> IfLet<'hir> {
-    #[inline]
-    pub fn ast(cx: &LateContext<'tcx>, expr: &Expr<'hir>) -> Option<Self> {
-        let rslt = Self::hir(expr)?;
-        Self::is_not_within_while_context(cx, expr)?;
-        Some(rslt)
-    }
-
-    #[inline]
-    pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
+    pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
         if let ExprKind::If(
             Expr {
                 kind: ExprKind::Let(let_pat, let_expr, _),
@@ -97,6 +89,14 @@ impl<'hir> IfLet<'hir> {
             if_else,
         ) = expr.kind
         {
+            let hir = cx.tcx.hir();
+            let mut iter = hir.parent_iter(expr.hir_id);
+            if let Some((_, Node::Block(Block { stmts: [], .. }))) = iter.next() {
+                if let Some((_, Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::While, _), .. }))) = iter.next() {
+                    // while loop desugar
+                    return None;
+                }
+            }
             return Some(Self {
                 let_pat,
                 let_expr,
@@ -106,22 +106,6 @@ impl<'hir> IfLet<'hir> {
         }
         None
     }
-
-    #[inline]
-    fn is_not_within_while_context(cx: &LateContext<'tcx>, expr: &Expr<'hir>) -> Option<()> {
-        let hir = cx.tcx.hir();
-        let parent = hir.get_parent_node(expr.hir_id);
-        let parent_parent = hir.get_parent_node(parent);
-        let parent_parent_node = hir.get(parent_parent);
-        if let Node::Expr(Expr {
-            kind: ExprKind::Loop(_, _, LoopSource::While, _),
-            ..
-        }) = parent_parent_node
-        {
-            return None;
-        }
-        Some(())
-    }
 }
 
 pub struct IfOrIfLet<'hir> {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 82bfce8fe78..2777e5bd0c4 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -254,6 +254,10 @@ pub fn in_macro(span: Span) -> bool {
     }
 }
 
+pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
+    matches!(expr.kind, ExprKind::Block(Block { stmts: [], expr: None, .. }, _) | ExprKind::Tup([]))
+}
+
 /// Checks if given pattern is a wildcard (`_`)
 pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
@@ -877,7 +881,7 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
     let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
     let line_no = source_map_and_line.line;
     let line_start = source_map_and_line.sf.lines[line_no];
-    Span::new(line_start, span.hi(), span.ctxt())
+    span.with_lo(line_start)
 }
 
 /// Gets the parent node, if any.
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index dee9d487c78..8e544f58066 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -36,6 +36,9 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&Ru
                 ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
+                ty::PredicateKind::Coerce(_) => {
+                    panic!("coerce predicate on function: {:#?}", predicate)
+                },
                 ty::PredicateKind::Trait(pred) => {
                     if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                         continue;
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 55467cf4229..4ce365cc764 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -98,6 +98,11 @@ fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>
 }
 
 fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u32, String>, String>) {
+    while let Some(x) = make() {
+        if let Some(1) = x {
+            todo!();
+        }
+    }
     // no wild pattern in outer match
     match res_opt {
         Ok(val) => match val {
diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr
index f96917f5833..c119570e8ab 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match.stderr
@@ -1,4 +1,4 @@
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match.rs:7:20
    |
 LL |           Ok(val) => match val {
@@ -17,7 +17,7 @@ LL |         Ok(val) => match val {
 LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match.rs:16:20
    |
 LL |           Ok(val) => match val {
@@ -35,7 +35,7 @@ LL |         Ok(val) => match val {
 LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
-error: unnecessary nested `if let` or `match`
+error: this `if let` can be collapsed into the outer `if let`
   --> $DIR/collapsible_match.rs:25:9
    |
 LL | /         if let Some(n) = val {
@@ -51,7 +51,7 @@ LL |     if let Ok(val) = res_opt {
 LL |         if let Some(n) = val {
    |                ^^^^^^^ with this pattern
 
-error: unnecessary nested `if let` or `match`
+error: this `if let` can be collapsed into the outer `if let`
   --> $DIR/collapsible_match.rs:32:9
    |
 LL | /         if let Some(n) = val {
@@ -69,7 +69,7 @@ LL |     if let Ok(val) = res_opt {
 LL |         if let Some(n) = val {
    |                ^^^^^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `if let`
   --> $DIR/collapsible_match.rs:43:9
    |
 LL | /         match val {
@@ -87,7 +87,7 @@ LL |         match val {
 LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
-error: unnecessary nested `if let` or `match`
+error: this `if let` can be collapsed into the outer `match`
   --> $DIR/collapsible_match.rs:52:13
    |
 LL | /             if let Some(n) = val {
@@ -103,7 +103,7 @@ LL |         Ok(val) => {
 LL |             if let Some(n) = val {
    |                    ^^^^^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `if let`
   --> $DIR/collapsible_match.rs:61:9
    |
 LL | /         match val {
@@ -121,7 +121,7 @@ LL |         match val {
 LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
-error: unnecessary nested `if let` or `match`
+error: this `if let` can be collapsed into the outer `match`
   --> $DIR/collapsible_match.rs:72:13
    |
 LL | /             if let Some(n) = val {
@@ -139,7 +139,7 @@ LL |         Ok(val) => {
 LL |             if let Some(n) = val {
    |                    ^^^^^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match.rs:83:20
    |
 LL |           Ok(val) => match val {
@@ -157,7 +157,7 @@ LL |         Ok(val) => match val {
 LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match.rs:92:22
    |
 LL |           Some(val) => match val {
diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr
index 8975b2efbae..55e70dce208 100644
--- a/src/tools/clippy/tests/ui/collapsible_match2.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr
@@ -1,4 +1,4 @@
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match2.rs:13:34
    |
 LL |               Ok(val) if make() => match val {
@@ -17,7 +17,7 @@ LL |             Ok(val) if make() => match val {
 LL |                 Some(n) => foo(n),
    |                 ^^^^^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match2.rs:20:24
    |
 LL |               Ok(val) => match val {
@@ -35,7 +35,7 @@ LL |             Ok(val) => match val {
 LL |                 Some(n) => foo(n),
    |                 ^^^^^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match2.rs:34:29
    |
 LL |                       $pat => match $e {
@@ -57,7 +57,7 @@ LL |         mac!(res_opt => Ok(val), val => Some(n), foo(n));
    |                            replace this binding
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match2.rs:51:20
    |
 LL |           Some(s) => match *s {
@@ -75,7 +75,7 @@ LL |         Some(s) => match *s {
 LL |             [n] => foo(n),
    |             ^^^ with this pattern
 
-error: unnecessary nested match
+error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match2.rs:60:24
    |
 LL |           Some(ref s) => match &*s {
diff --git a/src/tools/clippy/tests/ui/if_let_some_result.fixed b/src/tools/clippy/tests/ui/if_let_some_result.fixed
index 62a25ce2d12..1bddc47721e 100644
--- a/src/tools/clippy/tests/ui/if_let_some_result.fixed
+++ b/src/tools/clippy/tests/ui/if_let_some_result.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::if_let_some_result)]
+#![allow(dead_code)]
 
 fn str_to_int(x: &str) -> i32 {
     if let Ok(y) = x.parse() { y } else { 0 }
@@ -20,8 +21,8 @@ fn strange_some_no_else(x: &str) -> i32 {
     }
 }
 
-fn main() {
-    let _ = str_to_int("1");
-    let _ = str_to_int_ok("2");
-    let _ = strange_some_no_else("3");
+fn negative() {
+    while let Some(1) = "".parse().ok() {}
 }
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_let_some_result.rs b/src/tools/clippy/tests/ui/if_let_some_result.rs
index 234ff5e9e80..d4a52ec9881 100644
--- a/src/tools/clippy/tests/ui/if_let_some_result.rs
+++ b/src/tools/clippy/tests/ui/if_let_some_result.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::if_let_some_result)]
+#![allow(dead_code)]
 
 fn str_to_int(x: &str) -> i32 {
     if let Some(y) = x.parse().ok() { y } else { 0 }
@@ -20,8 +21,8 @@ fn strange_some_no_else(x: &str) -> i32 {
     }
 }
 
-fn main() {
-    let _ = str_to_int("1");
-    let _ = str_to_int_ok("2");
-    let _ = strange_some_no_else("3");
+fn negative() {
+    while let Some(1) = "".parse().ok() {}
 }
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_let_some_result.stderr b/src/tools/clippy/tests/ui/if_let_some_result.stderr
index 134ce9d2411..bc3a5e7698d 100644
--- a/src/tools/clippy/tests/ui/if_let_some_result.stderr
+++ b/src/tools/clippy/tests/ui/if_let_some_result.stderr
@@ -1,5 +1,5 @@
 error: matching on `Some` with `ok()` is redundant
-  --> $DIR/if_let_some_result.rs:6:5
+  --> $DIR/if_let_some_result.rs:7:5
    |
 LL |     if let Some(y) = x.parse().ok() { y } else { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -11,7 +11,7 @@ LL |     if let Ok(y) = x.parse() { y } else { 0 }
    |     ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: matching on `Some` with `ok()` is redundant
-  --> $DIR/if_let_some_result.rs:16:9
+  --> $DIR/if_let_some_result.rs:17:9
    |
 LL |         if let Some(y) = x   .   parse()   .   ok   ()    {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 5664a2b0b31403024ce5ab927760d630d5ddc9a
+Subproject b641a66078ce2f2363e9a3b050ba448b93fb7cb