about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml11
-rw-r--r--Cargo.lock32
-rw-r--r--RELEASES.md15
-rw-r--r--compiler/rustc_ast/src/ast.rs37
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs11
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs21
-rw-r--r--compiler/rustc_ast/src/util/comments.rs29
-rw-r--r--compiler/rustc_ast/src/util/comments/tests.rs14
-rw-r--r--compiler/rustc_ast/src/visit.rs20
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs18
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs14
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs16
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs15
-rw-r--r--compiler/rustc_ast_passes/src/node_count.rs4
-rw-r--r--compiler/rustc_ast_pretty/Cargo.toml1
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs371
-rw-r--r--compiler/rustc_ast_pretty/src/pp/ring.rs77
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs1240
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs571
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs644
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs205
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs59
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs162
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs19
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs143
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs150
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs180
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs6
-rw-r--r--compiler/rustc_driver/src/lib.rs7
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0038.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0183.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0521.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0581.md2
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs10
-rw-r--r--compiler/rustc_hir/src/definitions.rs8
-rw-r--r--compiler/rustc_hir/src/hir.rs41
-rw-r--r--compiler/rustc_hir/src/intravisit.rs11
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs9
-rw-r--r--compiler/rustc_incremental/src/persist/file_format.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs31
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs109
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs19
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs90
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs3
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs3
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_interface/src/util.rs13
-rw-r--r--compiler/rustc_lint/src/builtin.rs6
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp19
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs4
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs8
-rw-r--r--compiler/rustc_middle/src/middle/region.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs22
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs2
-rw-r--r--compiler/rustc_middle/src/thir.rs2
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs13
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs33
-rw-r--r--compiler/rustc_middle/src/ty/context.rs27
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs12
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs14
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs33
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs61
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs26
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs20
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs4
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs8
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs19
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs43
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs17
-rw-r--r--compiler/rustc_parse/src/parser/path.rs82
-rw-r--r--compiler/rustc_passes/src/check_attr.rs21
-rw-r--r--compiler/rustc_passes/src/dead.rs60
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs6
-rw-r--r--compiler/rustc_passes/src/intrinsicck.rs16
-rw-r--r--compiler/rustc_passes/src/lib.rs1
-rw-r--r--compiler/rustc_passes/src/region.rs11
-rw-r--r--compiler/rustc_privacy/src/lib.rs26
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs11
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs4
-rw-r--r--compiler/rustc_session/src/config.rs5
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_span/src/def_id.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs15
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs11
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs8
-rw-r--r--compiler/rustc_target/src/asm/arm.rs32
-rw-r--r--compiler/rustc_target/src/asm/avr.rs3
-rw-r--r--compiler/rustc_target/src/asm/bpf.rs10
-rw-r--r--compiler/rustc_target/src/asm/hexagon.rs3
-rw-r--r--compiler/rustc_target/src/asm/mips.rs3
-rw-r--r--compiler/rustc_target/src/asm/mod.rs74
-rw-r--r--compiler/rustc_target/src/asm/nvptx.rs3
-rw-r--r--compiler/rustc_target/src/asm/powerpc.rs3
-rw-r--r--compiler/rustc_target/src/asm/riscv.rs10
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs3
-rw-r--r--compiler/rustc_target/src/asm/spirv.rs3
-rw-r--r--compiler/rustc_target/src/asm/wasm.rs3
-rw-r--r--compiler/rustc_target/src/asm/x86.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/relationships.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs7
-rw-r--r--compiler/rustc_traits/Cargo.toml6
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs20
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs8
-rw-r--r--compiler/rustc_typeck/Cargo.toml2
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs8
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs62
-rw-r--r--compiler/rustc_typeck/src/bounds.rs46
-rw-r--r--compiler/rustc_typeck/src/check/check.rs29
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs8
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs2
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs18
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs48
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs269
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs473
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs92
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs77
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs118
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs25
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs26
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs8
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs31
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs160
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs6
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs5
-rw-r--r--compiler/rustc_typeck/src/constrained_generic_params.rs2
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_typeck/src/variance/constraints.rs13
-rw-r--r--library/alloc/src/raw_vec.rs2
-rw-r--r--library/alloc/src/slice.rs5
-rw-r--r--library/alloc/src/vec/mod.rs4
-rw-r--r--library/alloc/src/vec/spec_from_iter_nested.rs10
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/core/src/future/pending.rs5
-rw-r--r--library/core/src/hash/mod.rs2
-rw-r--r--library/core/src/iter/sources/empty.rs12
-rw-r--r--library/core/src/mem/maybe_uninit.rs129
-rw-r--r--library/core/src/num/bignum.rs42
-rw-r--r--library/core/src/num/f32.rs2
-rw-r--r--library/core/src/num/f64.rs2
-rw-r--r--library/core/src/num/int_log10.rs247
-rw-r--r--library/core/src/num/int_macros.rs6
-rw-r--r--library/core/src/num/mod.rs16
-rw-r--r--library/core/src/num/nonzero.rs52
-rw-r--r--library/core/src/num/uint_macros.rs17
-rw-r--r--library/core/src/option.rs23
-rw-r--r--library/core/src/result.rs47
-rw-r--r--library/core/src/sync/atomic.rs1
-rw-r--r--library/std/src/ffi/c_str.rs67
-rw-r--r--library/std/src/fs.rs14
-rw-r--r--library/std/src/fs/tests.rs70
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/panicking.rs2
-rw-r--r--library/std/src/path.rs2
-rw-r--r--library/std/src/sys/unix/fs.rs285
-rw-r--r--library/std/src/sys/unix/weak.rs6
-rw-r--r--library/std/src/sys/wasi/fs.rs71
-rw-r--r--library/std/src/sys/windows/c.rs124
-rw-r--r--library/std/src/sys/windows/fs.rs322
-rw-r--r--library/std/src/sys_common/backtrace.rs25
m---------library/stdarch0
-rw-r--r--src/bootstrap/bootstrap.py2
-rw-r--r--src/bootstrap/bootstrap_test.py4
-rw-r--r--src/bootstrap/compile.rs6
-rw-r--r--src/bootstrap/dist.rs3
-rw-r--r--src/ci/github-actions/ci.yml5
-rwxr-xr-xsrc/ci/scripts/verify-stable-version-number.sh30
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/command-line-arguments.md6
-rw-r--r--src/doc/rustc/src/platform-support/TEMPLATE.md52
-rw-r--r--src/doc/rustc/src/target-tier-policy.md43
-rw-r--r--src/etc/check_missing_items.py4
-rw-r--r--src/etc/htmldocck.py14
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/askama.toml2
-rw-r--r--src/librustdoc/clean/auto_trait.rs8
-rw-r--r--src/librustdoc/clean/cfg.rs53
-rw-r--r--src/librustdoc/clean/mod.rs57
-rw-r--r--src/librustdoc/clean/simplify.rs10
-rw-r--r--src/librustdoc/clean/types.rs39
-rw-r--r--src/librustdoc/core.rs6
-rw-r--r--src/librustdoc/html/format.rs18
-rw-r--r--src/librustdoc/html/markdown.rs4
-rw-r--r--src/librustdoc/html/render/context.rs12
-rw-r--r--src/librustdoc/html/render/mod.rs128
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css362
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css33
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css33
-rw-r--r--src/librustdoc/html/static/css/themes/light.css35
-rw-r--r--src/librustdoc/html/static/js/main.js96
-rw-r--r--src/librustdoc/html/static/js/search.js18
-rw-r--r--src/librustdoc/html/static/js/settings.js28
-rw-r--r--src/librustdoc/html/static/js/source-script.js2
-rw-r--r--src/librustdoc/html/static/js/storage.js11
-rw-r--r--src/librustdoc/html/templates/STYLE.md (renamed from src/librustdoc/templates/STYLE.md)0
-rw-r--r--src/librustdoc/html/templates/page.html (renamed from src/librustdoc/templates/page.html)16
-rw-r--r--src/librustdoc/html/templates/print_item.html (renamed from src/librustdoc/templates/print_item.html)0
-rw-r--r--src/librustdoc/json/conversions.rs11
-rw-r--r--src/librustdoc/json/mod.rs27
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs88
-rw-r--r--src/librustdoc/visit_ast.rs1
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs11
-rw-r--r--src/test/codegen/thread-local.rs4
-rw-r--r--src/test/incremental/cache_file_headers.rs2
-rw-r--r--src/test/run-make-fulldeps/codegen-options-parsing/Makefile4
-rw-r--r--src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile2
-rw-r--r--src/test/run-make-fulldeps/interdependent-c-libraries/Makefile2
-rw-r--r--src/test/run-make-fulldeps/link-arg/Makefile2
-rw-r--r--src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile2
-rw-r--r--src/test/run-make-fulldeps/no-builtins-lto/Makefile2
-rw-r--r--src/test/run-make-fulldeps/redundant-libs/Makefile2
-rw-r--r--src/test/run-make-fulldeps/static-nobundle/Makefile4
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/Makefile7
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/lib.rs7
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/output.txt2
-rw-r--r--src/test/run-make/raw-dylib-c/Makefile7
-rw-r--r--src/test/run-make/raw-dylib-link-ordinal/Makefile6
-rw-r--r--src/test/run-make/raw-dylib-stdcall-ordinal/Makefile23
-rw-r--r--src/test/run-make/raw-dylib-stdcall-ordinal/driver.rs5
-rw-r--r--src/test/run-make/raw-dylib-stdcall-ordinal/expected_output.txt2
-rw-r--r--src/test/run-make/raw-dylib-stdcall-ordinal/exporter-gnu.def4
-rw-r--r--src/test/run-make/raw-dylib-stdcall-ordinal/exporter-msvc.def4
-rw-r--r--src/test/run-make/raw-dylib-stdcall-ordinal/exporter.c11
-rw-r--r--src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs20
-rw-r--r--src/test/rustdoc-gui/anchors.goml2
-rw-r--r--src/test/rustdoc-gui/code-blocks-overflow.goml2
-rw-r--r--src/test/rustdoc-gui/docblock-table-overflow.goml4
-rw-r--r--src/test/rustdoc-gui/headings.goml19
-rw-r--r--src/test/rustdoc-gui/item-info-width.goml2
-rw-r--r--src/test/rustdoc-gui/mobile.goml17
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml2
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile.goml31
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code.goml4
-rw-r--r--src/test/rustdoc-gui/sidebar.goml16
-rw-r--r--src/test/rustdoc-gui/src/staged_api/Cargo.lock7
-rw-r--r--src/test/rustdoc-gui/src/staged_api/Cargo.toml11
-rw-r--r--src/test/rustdoc-gui/src/staged_api/lib.rs10
-rw-r--r--src/test/rustdoc-gui/toggle-docs-mobile.goml12
-rw-r--r--src/test/rustdoc-gui/type-declation-overflow.goml11
-rw-r--r--src/test/rustdoc-json/enums/variant_struct.rs4
-rw-r--r--src/test/rustdoc-json/enums/variant_tuple_struct.rs2
-rw-r--r--src/test/rustdoc-json/impls/blanket_with_local.rs14
-rw-r--r--src/test/rustdoc/cap-lints.rs2
-rw-r--r--src/test/rustdoc/const-display.rs17
-rw-r--r--src/test/rustdoc/crate-version-escape.rs3
-rw-r--r--src/test/rustdoc/crate-version.rs2
-rw-r--r--src/test/rustdoc/deref-const-fn.rs2
-rw-r--r--src/test/rustdoc/doc-auto-cfg.rs10
-rw-r--r--src/test/rustdoc/doc-cfg-hide.rs2
-rw-r--r--src/test/rustdoc/strip-block-doc-comments-stars.docblock.html2
-rw-r--r--src/test/rustdoc/strip-block-doc-comments-stars.rs11
-rw-r--r--src/test/rustdoc/titles.rs7
-rw-r--r--src/test/rustdoc/typedef.rs2
-rw-r--r--src/test/ui/associated-consts/assoc-const.rs21
-rw-r--r--src/test/ui/associated-consts/assoc-const.stderr14
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.rs25
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.stderr51
-rw-r--r--src/test/ui/async-await/issue-76547.stderr14
-rw-r--r--src/test/ui/async-await/issues/issue-63388-1.stderr6
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr5
-rw-r--r--src/test/ui/async-await/partial-drop-partial-reinit.rs29
-rw-r--r--src/test/ui/async-await/partial-drop-partial-reinit.stderr27
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs8
-rw-r--r--src/test/ui/async-await/unresolved_type_param.stderr26
-rw-r--r--src/test/ui/autoref-autoderef/deref-into-array.rs17
-rw-r--r--src/test/ui/const-generics/deref-into-array-generic.rs27
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs12
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr9
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/in-signature.rs61
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/in-signature.stderr119
-rw-r--r--src/test/ui/const-generics/issues/issue-92186.rs12
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs3
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr31
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013.rs3
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr31
-rw-r--r--src/test/ui/const-generics/types-mismatch-const-args.full.stderr17
-rw-r--r--src/test/ui/const-generics/types-mismatch-const-args.min.stderr13
-rw-r--r--src/test/ui/const-generics/types-mismatch-const-args.rs2
-rw-r--r--src/test/ui/consts/const-block-const-bound.rs8
-rw-r--r--src/test/ui/consts/const-block-const-bound.stderr18
-rw-r--r--src/test/ui/derive-uninhabited-enum-38885.stderr6
-rw-r--r--src/test/ui/derives/clone-debug-dead-code.stderr21
-rw-r--r--src/test/ui/did_you_mean/bad-assoc-ty.rs20
-rw-r--r--src/test/ui/did_you_mean/bad-assoc-ty.stderr20
-rw-r--r--src/test/ui/error-codes/E0121.stderr4
-rw-r--r--src/test/ui/expr/if/attrs/let-chains-attr.rs2
-rw-r--r--src/test/ui/expr/if/attrs/let-chains-attr.stderr11
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_const_equality.rs16
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr18
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr18
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib.rs (renamed from src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs)3
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib.stderr (renamed from src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr)2
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs47
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr441
-rw-r--r--src/test/ui/fn/issue-80179.rs4
-rw-r--r--src/test/ui/fn/issue-80179.stderr4
-rw-r--r--src/test/ui/generator/drop-control-flow.rs121
-rw-r--r--src/test/ui/generator/drop-yield-twice.rs15
-rw-r--r--src/test/ui/generator/drop-yield-twice.stderr25
-rw-r--r--src/test/ui/generator/issue-57478.rs16
-rw-r--r--src/test/ui/generator/partial-drop.rs40
-rw-r--r--src/test/ui/generator/partial-drop.stderr71
-rw-r--r--src/test/ui/generator/reinit-in-match-guard.rs25
-rw-r--r--src/test/ui/hygiene/rustc-macro-transparency.stderr28
-rw-r--r--src/test/ui/issues/issue-69396-const-no-type-in-macro.rs2
-rw-r--r--src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr2
-rw-r--r--src/test/ui/lint/dead-code/unused-variant.stderr6
-rw-r--r--src/test/ui/lint/must_not_suspend/dedup.rs2
-rw-r--r--src/test/ui/lint/must_not_suspend/dedup.stderr12
-rw-r--r--src/test/ui/macros/macro-interpolation.rs14
-rw-r--r--src/test/ui/mir/mir_let_chains_drop_order.rs93
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.rs6
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.stderr23
-rw-r--r--src/test/ui/pattern/issue-82290.rs9
-rw-r--r--src/test/ui/pattern/issue-82290.stderr21
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.fixed11
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.rs7
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.stderr45
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.rs32
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr48
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs15
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs2
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout2
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs20
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr21
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs1
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr221
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.rs64
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr96
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs37
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-88498.rs16
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-90722.rs11
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-92145.rs11
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs9
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs49
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs2
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr4
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs8
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr17
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr2
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr21
-rw-r--r--src/test/ui/self/elision/lt-ref-self-async.stderr54
-rw-r--r--src/test/ui/self/elision/ref-mut-self-async.stderr54
-rw-r--r--src/test/ui/self/elision/ref-mut-struct-async.stderr45
-rw-r--r--src/test/ui/self/elision/ref-self-async.stderr63
-rw-r--r--src/test/ui/self/elision/ref-struct-async.stderr45
-rw-r--r--src/test/ui/self/self-infer.rs4
-rw-r--r--src/test/ui/self/self-infer.stderr4
-rw-r--r--src/test/ui/simd/intrinsic/generic-as.rs48
-rw-r--r--src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs21
-rw-r--r--src/test/ui/specialization/min_specialization/repeated_projection_type.stderr2
-rw-r--r--src/test/ui/suggestions/unnamable-types.rs4
-rw-r--r--src/test/ui/suggestions/unnamable-types.stderr4
-rw-r--r--src/test/ui/symbol-names/foreign-types.rs19
-rw-r--r--src/test/ui/symbol-names/foreign-types.stderr20
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of.rs44
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of.stderr15
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs19
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr34
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.rs13
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr11
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs38
-rw-r--r--src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr82
-rw-r--r--src/test/ui/transmute/transmute-imut-to-mut.rs2
-rw-r--r--src/test/ui/transmute/transmute-imut-to-mut.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-77179.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-77179.stderr2
-rw-r--r--src/test/ui/typeck/issue-74086.rs2
-rw-r--r--src/test/ui/typeck/issue-74086.stderr2
-rw-r--r--src/test/ui/typeck/issue-75883.rs4
-rw-r--r--src/test/ui/typeck/issue-75883.stderr4
-rw-r--r--src/test/ui/typeck/issue-75889.stderr4
-rw-r--r--src/test/ui/typeck/issue-80779.rs4
-rw-r--r--src/test/ui/typeck/issue-80779.stderr4
-rw-r--r--src/test/ui/typeck/issue-81885.rs4
-rw-r--r--src/test/ui/typeck/issue-81885.stderr4
-rw-r--r--src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr2
-rw-r--r--src/test/ui/typeck/issue-91450-inner-ty-error.rs2
-rw-r--r--src/test/ui/typeck/issue-91450-inner-ty-error.stderr2
-rw-r--r--src/test/ui/typeck/type-placeholder-fn-in-const.rs6
-rw-r--r--src/test/ui/typeck/type-placeholder-fn-in-const.stderr6
-rw-r--r--src/test/ui/typeck/typeck_type_placeholder_item.rs120
-rw-r--r--src/test/ui/typeck/typeck_type_placeholder_item.stderr120
-rw-r--r--src/test/ui/typeck/typeck_type_placeholder_item_help.rs12
-rw-r--r--src/test/ui/typeck/typeck_type_placeholder_item_help.stderr12
-rw-r--r--src/tools/build-manifest/README.md3
-rw-r--r--src/tools/build-manifest/src/main.rs98
-rw-r--r--src/tools/build-manifest/src/versions.rs8
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md1
-rw-r--r--src/tools/clippy/COPYRIGHT2
-rw-r--r--src/tools/clippy/LICENSE-APACHE2
-rw-r--r--src/tools/clippy/LICENSE-MIT2
-rw-r--r--src/tools/clippy/README.md2
-rw-r--r--src/tools/clippy/clippy_lints/src/bit_mask.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_perf.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs94
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs14
-rw-r--r--src/tools/clippy/rustc_tools_util/README.md2
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed29
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs29
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr18
-rw-r--r--src/tools/clippy/tests/ui/format.fixed6
-rw-r--r--src/tools/clippy/tests/ui/format.rs6
-rw-r--r--src/tools/clippy/tests/ui/format.stderr14
-rw-r--r--src/tools/clippy/tests/ui/functions.rs8
-rw-r--r--src/tools/clippy/tests/ui/functions.stderr26
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.rs17
-rw-r--r--src/tools/clippy/tests/ui/implicit_clone.rs9
-rw-r--r--src/tools/clippy/tests/ui/implicit_clone.stderr54
-rw-r--r--src/tools/clippy/tests/ui/iter_not_returning_iterator.rs7
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.fixed45
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.rs47
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.stderr58
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed48
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs50
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr54
-rw-r--r--src/tools/clippy/tests/ui/return_self_not_must_use.rs1
-rw-r--r--src/tools/clippy/tests/ui/return_self_not_must_use.stderr6
-rw-r--r--src/tools/clippy/util/gh-pages/index.html2
-rw-r--r--src/tools/compiletest/src/runtest.rs14
m---------src/tools/rust-analyzer34
-rw-r--r--src/tools/rust-demangler/tests/lib.rs32
-rw-r--r--src/tools/rustfmt/src/types.rs17
485 files changed, 10080 insertions, 4911 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 67deb3d9779..1f872569ab1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -128,6 +128,9 @@ jobs:
       - name: ensure backported commits are in upstream branches
         run: src/ci/scripts/verify-backported-commits.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
@@ -320,7 +323,7 @@ jobs:
           - name: dist-aarch64-apple
             env:
               SCRIPT: "./x.py dist --stage 2"
-              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
@@ -502,6 +505,9 @@ jobs:
       - name: ensure backported commits are in upstream branches
         run: src/ci/scripts/verify-backported-commits.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
@@ -612,6 +618,9 @@ jobs:
       - name: ensure backported commits are in upstream branches
         run: src/ci/scripts/verify-backported-commits.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
diff --git a/Cargo.lock b/Cargo.lock
index 18b85103202..e0d2abc08fc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -152,7 +152,9 @@ dependencies = [
  "nom",
  "proc-macro2",
  "quote",
+ "serde",
  "syn",
+ "toml",
 ]
 
 [[package]]
@@ -326,7 +328,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.60.0"
+version = "0.61.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -335,7 +337,7 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap 3.0.6",
+ "clap 3.0.10",
  "crates-io",
  "crossbeam-utils",
  "curl",
@@ -542,9 +544,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54e3b5f9e3425e6b119ff07568d8d006bfa5a8d6f78a9cbc3530b1e962e316c"
+checksum = "58c24b8052ea1e3adbb6f9ab7ba5fcc18b9d12591c042de4c833f709ce81e0e0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -554,9 +556,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-engine"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdc891073396b167163db77123b0a3c00088edc00466cecc5531f33e3e989523"
+checksum = "0eca186b6ea9af798312f4b568fd094c82e7946ac08be5dc5fea22decc6d2ed8"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -567,9 +569,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b79e5a1d04b79311e90c69356a2c62027853906a7e33b3e070b93c055fc3e8a"
+checksum = "f3cad5c3f1edd4b4a2c9bda24ae558ceb4f88336f88f944c2e35d0bfeb13c818"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -578,13 +580,14 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5d2a1db6605aba70a58820bd80ac422b218913a510f1a40beef9efc5371ea1d"
+checksum = "94533188d3452bc72cbd5618d166f45fc7646b674ad3fe9667d557bc25236dee"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
  "ena",
+ "indexmap",
  "itertools 0.10.1",
  "petgraph",
  "rustc-hash",
@@ -624,9 +627,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.0.6"
+version = "3.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0"
+checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
 dependencies = [
  "atty",
  "bitflags",
@@ -836,7 +839,7 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
 
 [[package]]
 name = "crates-io"
-version = "0.33.1"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "curl",
@@ -3457,7 +3460,6 @@ version = "0.0.0"
 dependencies = [
  "rustc_ast",
  "rustc_span",
- "tracing",
 ]
 
 [[package]]
@@ -4412,6 +4414,7 @@ dependencies = [
  "rustc_attr",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_graphviz",
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_index",
@@ -4419,6 +4422,7 @@ dependencies = [
  "rustc_lint",
  "rustc_macros",
  "rustc_middle",
+ "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
diff --git a/RELEASES.md b/RELEASES.md
index 460c78b14d1..f44291c1fa3 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,18 @@
+Version 1.58.1 (2022-01-19)
+===========================
+
+* Fix race condition in `std::fs::remove_dir_all` ([CVE-2022-21658])
+* [Handle captured arguments in the `useless_format` Clippy lint][clippy/8295]
+* [Move `non_send_fields_in_send_ty` Clippy lint to nursery][clippy/8075]
+* [Fix wrong error message displayed when some imports are missing][91254]
+* [Fix rustfmt not formatting generated files from stdin][92912]
+
+[CVE-2022-21658]: https://www.cve.org/CVERecord?id=CVE-2022-21658]
+[91254]: https://github.com/rust-lang/rust/pull/91254
+[92912]: https://github.com/rust-lang/rust/pull/92912
+[clippy/8075]: https://github.com/rust-lang/rust-clippy/pull/8075
+[clippy/8295]: https://github.com/rust-lang/rust-clippy/pull/8295
+
 Version 1.58.0 (2022-01-13)
 ==========================
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 4692420206c..438168f4fcc 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -225,7 +225,7 @@ pub enum AngleBracketedArg {
     /// Argument for a generic parameter.
     Arg(GenericArg),
     /// Constraint for an associated item.
-    Constraint(AssocTyConstraint),
+    Constraint(AssocConstraint),
 }
 
 impl AngleBracketedArg {
@@ -1857,19 +1857,38 @@ impl UintTy {
 /// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
 /// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub struct AssocTyConstraint {
+pub struct AssocConstraint {
     pub id: NodeId,
     pub ident: Ident,
     pub gen_args: Option<GenericArgs>,
-    pub kind: AssocTyConstraintKind,
+    pub kind: AssocConstraintKind,
     pub span: Span,
 }
 
-/// The kinds of an `AssocTyConstraint`.
+/// The kinds of an `AssocConstraint`.
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub enum AssocTyConstraintKind {
-    /// E.g., `A = Bar` in `Foo<A = Bar>`.
-    Equality { ty: P<Ty> },
+pub enum Term {
+    Ty(P<Ty>),
+    Const(AnonConst),
+}
+
+impl From<P<Ty>> for Term {
+    fn from(v: P<Ty>) -> Self {
+        Term::Ty(v)
+    }
+}
+
+impl From<AnonConst> for Term {
+    fn from(v: AnonConst) -> Self {
+        Term::Const(v)
+    }
+}
+
+/// The kinds of an `AssocConstraint`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum AssocConstraintKind {
+    /// E.g., `A = Bar`, `A = 3` in `Foo<A = Bar>` where A is an associated type.
+    Equality { term: Term },
     /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
     Bound { bounds: GenericBounds },
 }
@@ -2001,7 +2020,7 @@ bitflags::bitflags! {
     }
 }
 
-#[derive(Clone, PartialEq, PartialOrd, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
 pub enum InlineAsmTemplatePiece {
     String(String),
     Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
@@ -2206,7 +2225,7 @@ pub enum IsAuto {
     No,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
 pub enum Unsafe {
     Yes(Span),
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index d66774040f7..6a0ace04d4b 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -242,6 +242,17 @@ impl Attribute {
         }
     }
 
+    pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
+        match self.kind {
+            AttrKind::DocComment(kind, data) => Some((data, kind)),
+            AttrKind::Normal(ref item, _) if item.path == sym::doc => item
+                .meta_kind()
+                .and_then(|kind| kind.value_str())
+                .map(|data| (data, CommentKind::Line)),
+            _ => None,
+        }
+    }
+
     pub fn doc_str(&self) -> Option<Symbol> {
         match self.kind {
             AttrKind::DocComment(.., data) => Some(data),
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 564a8a8c872..a81a2276295 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -165,8 +165,8 @@ pub trait MutVisitor: Sized {
         noop_visit_lifetime(l, self);
     }
 
-    fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
-        noop_visit_ty_constraint(t, self);
+    fn visit_constraint(&mut self, t: &mut AssocConstraint) {
+        noop_visit_constraint(t, self);
     }
 
     fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
@@ -430,8 +430,8 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
     smallvec![arm]
 }
 
-pub fn noop_visit_ty_constraint<T: MutVisitor>(
-    AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
+pub fn noop_visit_constraint<T: MutVisitor>(
+    AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
     vis: &mut T,
 ) {
     vis.visit_id(id);
@@ -440,12 +440,11 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
         vis.visit_generic_args(gen_args);
     }
     match kind {
-        AssocTyConstraintKind::Equality { ref mut ty } => {
-            vis.visit_ty(ty);
-        }
-        AssocTyConstraintKind::Bound { ref mut bounds } => {
-            visit_bounds(bounds, vis);
-        }
+        AssocConstraintKind::Equality { ref mut term } => match term {
+            Term::Ty(ty) => vis.visit_ty(ty),
+            Term::Const(c) => vis.visit_anon_const(c),
+        },
+        AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
     }
     vis.visit_span(span);
 }
@@ -555,7 +554,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
     let AngleBracketedArgs { args, span } = data;
     visit_vec(args, |arg| match arg {
         AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
-        AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
+        AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint),
     });
     vis.visit_span(span);
 }
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index 0a391123dd3..612ee71f350 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -1,3 +1,4 @@
+use crate::token::CommentKind;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol};
 
@@ -25,7 +26,7 @@ pub struct Comment {
 
 /// Makes a doc string more presentable to users.
 /// Used by rustdoc and perhaps other tools, but not by rustc.
-pub fn beautify_doc_string(data: Symbol) -> Symbol {
+pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
     fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> {
         let mut i = 0;
         let mut j = lines.len();
@@ -42,10 +43,28 @@ pub fn beautify_doc_string(data: Symbol) -> Symbol {
         if i != 0 || j != lines.len() { Some((i, j)) } else { None }
     }
 
-    fn get_horizontal_trim(lines: &[&str]) -> Option<usize> {
+    fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option<usize> {
         let mut i = usize::MAX;
         let mut first = true;
 
+        // In case we have doc comments like `/**` or `/*!`, we want to remove stars if they are
+        // present. However, we first need to strip the empty lines so they don't get in the middle
+        // when we try to compute the "horizontal trim".
+        let lines = if kind == CommentKind::Block {
+            let mut i = 0;
+            let mut j = lines.len();
+
+            while i < j && lines[i].trim().is_empty() {
+                i += 1;
+            }
+            while j > i && lines[j - 1].trim().is_empty() {
+                j -= 1;
+            }
+            &lines[i..j]
+        } else {
+            lines
+        };
+
         for line in lines {
             for (j, c) in line.chars().enumerate() {
                 if j > i || !"* \t".contains(c) {
@@ -79,11 +98,13 @@ pub fn beautify_doc_string(data: Symbol) -> Symbol {
         } else {
             &mut lines
         };
-        if let Some(horizontal) = get_horizontal_trim(&lines) {
+        if let Some(horizontal) = get_horizontal_trim(&lines, kind) {
             changes = true;
             // remove a "[ \t]*\*" block from each line, if possible
             for line in lines.iter_mut() {
-                *line = &line[horizontal + 1..];
+                if horizontal + 1 < line.len() {
+                    *line = &line[horizontal + 1..];
+                }
             }
         }
         if changes {
diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs
index 6d137f3774f..98f692a7724 100644
--- a/compiler/rustc_ast/src/util/comments/tests.rs
+++ b/compiler/rustc_ast/src/util/comments/tests.rs
@@ -5,7 +5,7 @@ use rustc_span::create_default_session_globals_then;
 fn test_block_doc_comment_1() {
     create_default_session_globals_then(|| {
         let comment = "\n * Test \n **  Test\n *   Test\n";
-        let stripped = beautify_doc_string(Symbol::intern(comment));
+        let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
         assert_eq!(stripped.as_str(), " Test \n*  Test\n   Test");
     })
 }
@@ -14,7 +14,7 @@ fn test_block_doc_comment_1() {
 fn test_block_doc_comment_2() {
     create_default_session_globals_then(|| {
         let comment = "\n * Test\n *  Test\n";
-        let stripped = beautify_doc_string(Symbol::intern(comment));
+        let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
         assert_eq!(stripped.as_str(), " Test\n  Test");
     })
 }
@@ -23,7 +23,7 @@ fn test_block_doc_comment_2() {
 fn test_block_doc_comment_3() {
     create_default_session_globals_then(|| {
         let comment = "\n let a: *i32;\n *a = 5;\n";
-        let stripped = beautify_doc_string(Symbol::intern(comment));
+        let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
         assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
     })
 }
@@ -31,13 +31,13 @@ fn test_block_doc_comment_3() {
 #[test]
 fn test_line_doc_comment() {
     create_default_session_globals_then(|| {
-        let stripped = beautify_doc_string(Symbol::intern(" test"));
+        let stripped = beautify_doc_string(Symbol::intern(" test"), CommentKind::Line);
         assert_eq!(stripped.as_str(), " test");
-        let stripped = beautify_doc_string(Symbol::intern("! test"));
+        let stripped = beautify_doc_string(Symbol::intern("! test"), CommentKind::Line);
         assert_eq!(stripped.as_str(), "! test");
-        let stripped = beautify_doc_string(Symbol::intern("test"));
+        let stripped = beautify_doc_string(Symbol::intern("test"), CommentKind::Line);
         assert_eq!(stripped.as_str(), "test");
-        let stripped = beautify_doc_string(Symbol::intern("!test"));
+        let stripped = beautify_doc_string(Symbol::intern("!test"), CommentKind::Line);
         assert_eq!(stripped.as_str(), "!test");
     })
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 0b95270a4e1..73e9297549c 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -190,8 +190,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
         walk_generic_arg(self, generic_arg)
     }
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
-        walk_assoc_ty_constraint(self, constraint)
+    fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
+        walk_assoc_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, attr: &'ast Attribute) {
         walk_attribute(self, attr)
@@ -464,7 +464,7 @@ where
             for arg in &data.args {
                 match arg {
                     AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
-                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
+                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_constraint(c),
                 }
             }
         }
@@ -486,19 +486,17 @@ where
     }
 }
 
-pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    constraint: &'a AssocTyConstraint,
-) {
+pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
     visitor.visit_ident(constraint.ident);
     if let Some(ref gen_args) = constraint.gen_args {
         visitor.visit_generic_args(gen_args.span(), gen_args);
     }
     match constraint.kind {
-        AssocTyConstraintKind::Equality { ref ty } => {
-            visitor.visit_ty(ty);
-        }
-        AssocTyConstraintKind::Bound { ref bounds } => {
+        AssocConstraintKind::Equality { ref term } => match term {
+            Term::Ty(ty) => visitor.visit_ty(ty),
+            Term::Const(c) => visitor.visit_anon_const(c),
+        },
+        AssocConstraintKind::Bound { ref bounds } => {
             walk_list!(visitor, visit_param_bound, bounds);
         }
     }
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 9c28f3c7f58..89d411d4b36 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_session::parse::feature_err;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{sym, Span};
 use rustc_target::asm;
 use std::collections::hash_map::Entry;
 use std::fmt::Write;
@@ -66,7 +66,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             for (abi_name, abi_span) in &asm.clobber_abis {
                 match asm::InlineAsmClobberAbi::parse(
                     asm_arch,
-                    |feature| self.sess.target_features.contains(&Symbol::intern(feature)),
+                    &self.sess.target_features,
                     &self.sess.target,
                     *abi_name,
                 ) {
@@ -134,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
                             asm::InlineAsmReg::parse(
                                 asm_arch,
-                                |feature| sess.target_features.contains(&Symbol::intern(feature)),
+                                &sess.target_features,
                                 &sess.target,
                                 s,
                             )
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 470e9114217..6c172d59f83 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -392,14 +392,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
     // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
     // in a temporary block.
     fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
-        match cond.kind {
-            hir::ExprKind::Let(..) => cond,
-            _ => {
-                let span_block =
-                    self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
-                self.expr_drop_temps(span_block, cond, AttrVec::new())
+        fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool {
+            match expr.kind {
+                hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+                hir::ExprKind::Let(..) => true,
+                _ => false,
             }
         }
+        if has_let_expr(cond) {
+            cond
+        } else {
+            let reason = DesugaringKind::CondTemporary;
+            let span_block = self.mark_span_with_reason(reason, cond.span, None);
+            self.expr_drop_temps(span_block, cond, AttrVec::new())
+        }
     }
 
     // We desugar: `'label: while $cond $body` into:
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 7eb08b8754a..47b61067055 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -960,7 +960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// returns a `hir::TypeBinding` representing `Item`.
     fn lower_assoc_ty_constraint(
         &mut self,
-        constraint: &AssocTyConstraint,
+        constraint: &AssocConstraint,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
@@ -997,10 +997,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
 
         let kind = match constraint.kind {
-            AssocTyConstraintKind::Equality { ref ty } => {
-                hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
+            AssocConstraintKind::Equality { ref term } => {
+                let term = match term {
+                    Term::Ty(ref ty) => self.lower_ty(ty, itctx).into(),
+                    Term::Const(ref c) => self.lower_anon_const(c).into(),
+                };
+                hir::TypeBindingKind::Equality { term }
             }
-            AssocTyConstraintKind::Bound { ref bounds } => {
+            AssocConstraintKind::Bound { ref bounds } => {
                 let mut capturable_lifetimes;
                 let mut parent_def_id = self.current_hir_id_owner;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
@@ -1078,7 +1082,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             itctx,
                         );
 
-                        hir::TypeBindingKind::Equality { ty }
+                        hir::TypeBindingKind::Equality { term: ty.into() }
                     })
                 } else {
                     // Desugar `AssocTy: Bounds` into a type binding where the
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 46928a18465..79262235cd9 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -420,7 +420,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         ty: &'hir hir::Ty<'hir>,
     ) -> hir::TypeBinding<'hir> {
         let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
-        let kind = hir::TypeBindingKind::Equality { ty };
+        let kind = hir::TypeBindingKind::Equality { term: ty.into() };
         let args = arena_vec![self;];
         let bindings = arena_vec![self;];
         let gen_args = self.arena.alloc(hir::GenericArgs {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 45920bb27d5..eb7c75cac05 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -138,10 +138,10 @@ impl<'a> AstValidator<'a> {
         self.outer_impl_trait = old;
     }
 
-    fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
+    fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
         match constraint.kind {
-            AssocTyConstraintKind::Equality { .. } => {}
-            AssocTyConstraintKind::Bound { .. } => {
+            AssocConstraintKind::Equality { .. } => {}
+            AssocConstraintKind::Bound { .. } => {
                 if self.is_assoc_ty_bound_banned {
                     self.err_handler().span_err(
                         constraint.span,
@@ -150,7 +150,7 @@ impl<'a> AstValidator<'a> {
                 }
             }
         }
-        self.visit_assoc_ty_constraint(constraint);
+        self.visit_assoc_constraint(constraint);
     }
 
     // Mirrors `visit::walk_ty`, but tracks relevant state.
@@ -1277,7 +1277,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         // are allowed to contain nested `impl Trait`.
                         AngleBracketedArg::Constraint(constraint) => {
                             self.with_impl_trait(None, |this| {
-                                this.visit_assoc_ty_constraint_from_generic_args(constraint);
+                                this.visit_assoc_constraint_from_generic_args(constraint);
                             });
                         }
                     }
@@ -1586,12 +1586,12 @@ fn deny_equality_constraints(
                                     let len = assoc_path.segments.len() - 1;
                                     let gen_args = args.as_ref().map(|p| (**p).clone());
                                     // Build `<Bar = RhsTy>`.
-                                    let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
+                                    let arg = AngleBracketedArg::Constraint(AssocConstraint {
                                         id: rustc_ast::node_id::DUMMY_NODE_ID,
                                         ident: *ident,
                                         gen_args,
-                                        kind: AssocTyConstraintKind::Equality {
-                                            ty: predicate.rhs_ty.clone(),
+                                        kind: AssocConstraintKind::Equality {
+                                            term: predicate.rhs_ty.clone().into(),
                                         },
                                         span: ident.span,
                                     });
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 85e35c942b9..a6ecfa45206 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,6 +1,6 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
+use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd, VariantData};
 use rustc_errors::struct_span_err;
 use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -622,8 +622,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_fn(self, fn_kind, span)
     }
 
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
-        if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
+    fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
+        if let AssocConstraintKind::Bound { .. } = constraint.kind {
             gate_feature_post!(
                 &self,
                 associated_type_bounds,
@@ -631,7 +631,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 "associated type bounds are unstable"
             )
         }
-        visit::walk_assoc_ty_constraint(self, constraint)
+        visit::walk_assoc_constraint(self, constraint)
     }
 
     fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
@@ -707,11 +707,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
         "`if let` guards are experimental",
         "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
     );
-    gate_all!(
-        let_chains,
-        "`let` expressions in this position are experimental",
-        "you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`"
-    );
+    gate_all!(let_chains, "`let` expressions in this position are unstable");
     gate_all!(
         async_closure,
         "async closures are unstable",
@@ -724,6 +720,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
     gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
+    gate_all!(associated_const_equality, "associated const equality is incomplete");
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 3980e6da682..a4a48cc8e8a 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -126,9 +126,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_generic_args(self, path_span, generic_args)
     }
-    fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
+    fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
         self.count += 1;
-        walk_assoc_ty_constraint(self, constraint)
+        walk_assoc_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, _attr: &Attribute) {
         self.count += 1;
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index 29f2be4cf46..5ad8714e9fe 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -7,6 +7,5 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-tracing = "0.1"
 rustc_span = { path = "../rustc_span" }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index 20954a322a5..82c40868d18 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -132,10 +132,12 @@
 //! methods called `Printer::scan_*`, and the 'PRINT' process is the
 //! method called `Printer::print`.
 
+mod ring;
+
+use ring::RingBuffer;
 use std::borrow::Cow;
 use std::collections::VecDeque;
-use std::fmt;
-use tracing::debug;
+use std::iter;
 
 /// How to break. Described in more detail in the module docs.
 #[derive(Clone, Copy, PartialEq)]
@@ -165,76 +167,30 @@ pub enum Token {
     Break(BreakToken),
     Begin(BeginToken),
     End,
-    Eof,
 }
 
 impl Token {
-    crate fn is_eof(&self) -> bool {
-        matches!(self, Token::Eof)
-    }
-
     pub fn is_hardbreak_tok(&self) -> bool {
         matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
     }
 }
 
-impl fmt::Display for Token {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Token::String(ref s) => write!(f, "STR({},{})", s, s.len()),
-            Token::Break(_) => f.write_str("BREAK"),
-            Token::Begin(_) => f.write_str("BEGIN"),
-            Token::End => f.write_str("END"),
-            Token::Eof => f.write_str("EOF"),
-        }
-    }
-}
-
-fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
-    let n = buf.len();
-    let mut i = left;
-    let mut l = lim;
-    let mut s = String::from("[");
-    while i != right && l != 0 {
-        l -= 1;
-        if i != left {
-            s.push_str(", ");
-        }
-        s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
-        i += 1;
-        i %= n;
-    }
-    s.push(']');
-    s
-}
-
 #[derive(Copy, Clone)]
-enum PrintStackBreak {
+enum PrintFrame {
     Fits,
-    Broken(Breaks),
-}
-
-#[derive(Copy, Clone)]
-struct PrintStackElem {
-    offset: isize,
-    pbreak: PrintStackBreak,
+    Broken { offset: isize, breaks: Breaks },
 }
 
 const SIZE_INFINITY: isize = 0xffff;
 
 pub struct Printer {
     out: String,
-    buf_max_len: usize,
     /// Width of lines we're constrained to
     margin: isize,
     /// Number of spaces left on line
     space: isize,
-    /// Index of left side of input stream
-    left: usize,
-    /// Index of right side of input stream
-    right: usize,
     /// Ring-buffer of tokens and calculated sizes
-    buf: Vec<BufEntry>,
+    buf: RingBuffer<BufEntry>,
     /// Running size of stream "...left"
     left_total: isize,
     /// Running size of stream "...right"
@@ -247,9 +203,12 @@ pub struct Printer {
     /// advancing.
     scan_stack: VecDeque<usize>,
     /// Stack of blocks-in-progress being flushed by print
-    print_stack: Vec<PrintStackElem>,
+    print_stack: Vec<PrintFrame>,
     /// Buffered indentation to avoid writing trailing whitespace
     pending_indentation: isize,
+    /// The token most recently popped from the left boundary of the
+    /// ring-buffer for printing
+    last_printed: Option<Token>,
 }
 
 #[derive(Clone)]
@@ -258,43 +217,34 @@ struct BufEntry {
     size: isize,
 }
 
-impl Default for BufEntry {
-    fn default() -> Self {
-        BufEntry { token: Token::Eof, size: 0 }
-    }
-}
-
 impl Printer {
     pub fn new() -> Self {
         let linewidth = 78;
-        // Yes 55, it makes the ring buffers big enough to never fall behind.
-        let n: usize = 55 * linewidth;
-        debug!("Printer::new {}", linewidth);
         Printer {
             out: String::new(),
-            buf_max_len: n,
             margin: linewidth as isize,
             space: linewidth as isize,
-            left: 0,
-            right: 0,
-            // Initialize a single entry; advance_right() will extend it on demand
-            // up to `buf_max_len` elements.
-            buf: vec![BufEntry::default()],
+            buf: RingBuffer::new(),
             left_total: 0,
             right_total: 0,
             scan_stack: VecDeque::new(),
             print_stack: Vec::new(),
             pending_indentation: 0,
+            last_printed: None,
         }
     }
 
-    pub fn last_token(&self) -> Token {
-        self.buf[self.right].token.clone()
+    pub fn last_token(&self) -> Option<&Token> {
+        self.last_token_still_buffered().or_else(|| self.last_printed.as_ref())
+    }
+
+    pub fn last_token_still_buffered(&self) -> Option<&Token> {
+        self.buf.last().map(|last| &last.token)
     }
 
     /// Be very careful with this!
-    pub fn replace_last_token(&mut self, t: Token) {
-        self.buf[self.right].token = t;
+    pub fn replace_last_token_still_buffered(&mut self, token: Token) {
+        self.buf.last_mut().unwrap().token = token;
     }
 
     fn scan_eof(&mut self) {
@@ -304,242 +254,156 @@ impl Printer {
         }
     }
 
-    fn scan_begin(&mut self, b: BeginToken) {
+    fn scan_begin(&mut self, token: BeginToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
-            self.left = 0;
-            self.right = 0;
-        } else {
-            self.advance_right();
+            self.buf.clear();
         }
-        debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
-        self.scan_push(BufEntry { token: Token::Begin(b), size: -self.right_total });
+        let right = self.buf.push(BufEntry { token: Token::Begin(token), size: -self.right_total });
+        self.scan_stack.push_back(right);
     }
 
     fn scan_end(&mut self) {
         if self.scan_stack.is_empty() {
-            debug!("pp End/print Vec<{},{}>", self.left, self.right);
             self.print_end();
         } else {
-            debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
-            self.advance_right();
-            self.scan_push(BufEntry { token: Token::End, size: -1 });
+            let right = self.buf.push(BufEntry { token: Token::End, size: -1 });
+            self.scan_stack.push_back(right);
         }
     }
 
-    fn scan_break(&mut self, b: BreakToken) {
+    fn scan_break(&mut self, token: BreakToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
-            self.left = 0;
-            self.right = 0;
+            self.buf.clear();
         } else {
-            self.advance_right();
+            self.check_stack(0);
         }
-        debug!("pp Break({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
-        self.check_stack(0);
-        self.scan_push(BufEntry { token: Token::Break(b), size: -self.right_total });
-        self.right_total += b.blank_space;
+        let right = self.buf.push(BufEntry { token: Token::Break(token), size: -self.right_total });
+        self.scan_stack.push_back(right);
+        self.right_total += token.blank_space;
     }
 
-    fn scan_string(&mut self, s: Cow<'static, str>) {
+    fn scan_string(&mut self, string: Cow<'static, str>) {
         if self.scan_stack.is_empty() {
-            debug!("pp String('{}')/print Vec<{},{}>", s, self.left, self.right);
-            self.print_string(s);
+            self.print_string(&string);
         } else {
-            debug!("pp String('{}')/buffer Vec<{},{}>", s, self.left, self.right);
-            self.advance_right();
-            let len = s.len() as isize;
-            self.buf[self.right] = BufEntry { token: Token::String(s), size: len };
+            let len = string.len() as isize;
+            self.buf.push(BufEntry { token: Token::String(string), size: len });
             self.right_total += len;
             self.check_stream();
         }
     }
 
     fn check_stream(&mut self) {
-        debug!(
-            "check_stream Vec<{}, {}> with left_total={}, right_total={}",
-            self.left, self.right, self.left_total, self.right_total
-        );
-        if self.right_total - self.left_total > self.space {
-            debug!(
-                "scan window is {}, longer than space on line ({})",
-                self.right_total - self.left_total,
-                self.space
-            );
-            if Some(&self.left) == self.scan_stack.back() {
-                debug!("setting {} to infinity and popping", self.left);
-                let scanned = self.scan_pop_bottom();
-                self.buf[scanned].size = SIZE_INFINITY;
+        while self.right_total - self.left_total > self.space {
+            if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
+                self.scan_stack.pop_front().unwrap();
+                self.buf.first_mut().unwrap().size = SIZE_INFINITY;
             }
             self.advance_left();
-            if self.left != self.right {
-                self.check_stream();
+            if self.buf.is_empty() {
+                break;
             }
         }
     }
 
-    fn scan_push(&mut self, entry: BufEntry) {
-        debug!("scan_push {}", self.right);
-        self.buf[self.right] = entry;
-        self.scan_stack.push_front(self.right);
-    }
-
-    fn scan_pop(&mut self) -> usize {
-        self.scan_stack.pop_front().unwrap()
-    }
-
-    fn scan_top(&self) -> usize {
-        *self.scan_stack.front().unwrap()
-    }
-
-    fn scan_pop_bottom(&mut self) -> usize {
-        self.scan_stack.pop_back().unwrap()
-    }
-
-    fn advance_right(&mut self) {
-        self.right += 1;
-        self.right %= self.buf_max_len;
-        // Extend the buf if necessary.
-        if self.right == self.buf.len() {
-            self.buf.push(BufEntry::default());
-        }
-        assert_ne!(self.right, self.left);
-    }
-
     fn advance_left(&mut self) {
-        debug!(
-            "advance_left Vec<{},{}>, sizeof({})={}",
-            self.left, self.right, self.left, self.buf[self.left].size
-        );
-
-        let mut left_size = self.buf[self.left].size;
-
-        while left_size >= 0 {
-            let left = self.buf[self.left].token.clone();
-
-            let len = match left {
-                Token::Break(b) => b.blank_space,
-                Token::String(ref s) => {
-                    let len = s.len() as isize;
-                    assert_eq!(len, left_size);
-                    len
-                }
-                _ => 0,
-            };
+        while self.buf.first().unwrap().size >= 0 {
+            let left = self.buf.pop_first().unwrap();
 
-            self.print(left, left_size);
+            match &left.token {
+                Token::String(string) => {
+                    self.left_total += string.len() as isize;
+                    self.print_string(string);
+                }
+                Token::Break(token) => {
+                    self.left_total += token.blank_space;
+                    self.print_break(*token, left.size);
+                }
+                Token::Begin(token) => self.print_begin(*token, left.size),
+                Token::End => self.print_end(),
+            }
 
-            self.left_total += len;
+            self.last_printed = Some(left.token);
 
-            if self.left == self.right {
+            if self.buf.is_empty() {
                 break;
             }
-
-            self.left += 1;
-            self.left %= self.buf_max_len;
-
-            left_size = self.buf[self.left].size;
         }
     }
 
-    fn check_stack(&mut self, k: usize) {
-        if !self.scan_stack.is_empty() {
-            let x = self.scan_top();
-            match self.buf[x].token {
+    fn check_stack(&mut self, mut depth: usize) {
+        while let Some(&index) = self.scan_stack.back() {
+            let mut entry = &mut self.buf[index];
+            match entry.token {
                 Token::Begin(_) => {
-                    if k > 0 {
-                        self.scan_pop();
-                        self.buf[x].size += self.right_total;
-                        self.check_stack(k - 1);
+                    if depth == 0 {
+                        break;
                     }
+                    self.scan_stack.pop_back().unwrap();
+                    entry.size += self.right_total;
+                    depth -= 1;
                 }
                 Token::End => {
                     // paper says + not =, but that makes no sense.
-                    self.scan_pop();
-                    self.buf[x].size = 1;
-                    self.check_stack(k + 1);
+                    self.scan_stack.pop_back().unwrap();
+                    entry.size = 1;
+                    depth += 1;
                 }
                 _ => {
-                    self.scan_pop();
-                    self.buf[x].size += self.right_total;
-                    if k > 0 {
-                        self.check_stack(k);
+                    self.scan_stack.pop_back().unwrap();
+                    entry.size += self.right_total;
+                    if depth == 0 {
+                        break;
                     }
                 }
             }
         }
     }
 
-    fn print_newline(&mut self, amount: isize) {
-        debug!("NEWLINE {}", amount);
-        self.out.push('\n');
-        self.pending_indentation = 0;
-        self.indent(amount);
-    }
-
-    fn indent(&mut self, amount: isize) {
-        debug!("INDENT {}", amount);
-        self.pending_indentation += amount;
-    }
-
-    fn get_top(&self) -> PrintStackElem {
-        *self.print_stack.last().unwrap_or({
-            &PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
-        })
+    fn get_top(&self) -> PrintFrame {
+        *self
+            .print_stack
+            .last()
+            .unwrap_or(&PrintFrame::Broken { offset: 0, breaks: Breaks::Inconsistent })
     }
 
-    fn print_begin(&mut self, b: BeginToken, l: isize) {
-        if l > self.space {
-            let col = self.margin - self.space + b.offset;
-            debug!("print Begin -> push broken block at col {}", col);
-            self.print_stack
-                .push(PrintStackElem { offset: col, pbreak: PrintStackBreak::Broken(b.breaks) });
+    fn print_begin(&mut self, token: BeginToken, size: isize) {
+        if size > self.space {
+            let col = self.margin - self.space + token.offset;
+            self.print_stack.push(PrintFrame::Broken { offset: col, breaks: token.breaks });
         } else {
-            debug!("print Begin -> push fitting block");
-            self.print_stack.push(PrintStackElem { offset: 0, pbreak: PrintStackBreak::Fits });
+            self.print_stack.push(PrintFrame::Fits);
         }
     }
 
     fn print_end(&mut self) {
-        debug!("print End -> pop End");
         self.print_stack.pop().unwrap();
     }
 
-    fn print_break(&mut self, b: BreakToken, l: isize) {
-        let top = self.get_top();
-        match top.pbreak {
-            PrintStackBreak::Fits => {
-                debug!("print Break({}) in fitting block", b.blank_space);
-                self.space -= b.blank_space;
-                self.indent(b.blank_space);
-            }
-            PrintStackBreak::Broken(Breaks::Consistent) => {
-                debug!("print Break({}+{}) in consistent block", top.offset, b.offset);
-                self.print_newline(top.offset + b.offset);
-                self.space = self.margin - (top.offset + b.offset);
-            }
-            PrintStackBreak::Broken(Breaks::Inconsistent) => {
-                if l > self.space {
-                    debug!("print Break({}+{}) w/ newline in inconsistent", top.offset, b.offset);
-                    self.print_newline(top.offset + b.offset);
-                    self.space = self.margin - (top.offset + b.offset);
-                } else {
-                    debug!("print Break({}) w/o newline in inconsistent", b.blank_space);
-                    self.indent(b.blank_space);
-                    self.space -= b.blank_space;
+    fn print_break(&mut self, token: BreakToken, size: isize) {
+        let break_offset =
+            match self.get_top() {
+                PrintFrame::Fits => None,
+                PrintFrame::Broken { offset, breaks: Breaks::Consistent } => Some(offset),
+                PrintFrame::Broken { offset, breaks: Breaks::Inconsistent } => {
+                    if size > self.space { Some(offset) } else { None }
                 }
-            }
+            };
+        if let Some(offset) = break_offset {
+            self.out.push('\n');
+            self.pending_indentation = offset + token.offset;
+            self.space = self.margin - (offset + token.offset);
+        } else {
+            self.pending_indentation += token.blank_space;
+            self.space -= token.blank_space;
         }
     }
 
-    fn print_string(&mut self, s: Cow<'static, str>) {
-        let len = s.len() as isize;
-        debug!("print String({})", s);
-        // assert!(len <= space);
-        self.space -= len;
-
+    fn print_string(&mut self, string: &str) {
         // Write the pending indent. A more concise way of doing this would be:
         //
         //   write!(self.out, "{: >n$}", "", n = self.pending_indentation as usize)?;
@@ -547,32 +411,18 @@ impl Printer {
         // But that is significantly slower. This code is sufficiently hot, and indents can get
         // sufficiently large, that the difference is significant on some workloads.
         self.out.reserve(self.pending_indentation as usize);
-        self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
+        self.out.extend(iter::repeat(' ').take(self.pending_indentation as usize));
         self.pending_indentation = 0;
-        self.out.push_str(&s);
-    }
 
-    fn print(&mut self, token: Token, l: isize) {
-        debug!("print {} {} (remaining line space={})", token, l, self.space);
-        debug!("{}", buf_str(&self.buf, self.left, self.right, 6));
-        match token {
-            Token::Begin(b) => self.print_begin(b, l),
-            Token::End => self.print_end(),
-            Token::Break(b) => self.print_break(b, l),
-            Token::String(s) => {
-                let len = s.len() as isize;
-                assert_eq!(len, l);
-                self.print_string(s);
-            }
-            Token::Eof => panic!(), // Eof should never get here.
-        }
+        self.out.push_str(string);
+        self.space -= string.len() as isize;
     }
 
     // Convenience functions to talk to the printer.
 
     /// "raw box"
-    pub fn rbox(&mut self, indent: usize, b: Breaks) {
-        self.scan_begin(BeginToken { offset: indent as isize, breaks: b })
+    pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
+        self.scan_begin(BeginToken { offset: indent as isize, breaks })
     }
 
     /// Inconsistent breaking box
@@ -599,8 +449,8 @@ impl Printer {
     }
 
     pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
-        let s = wrd.into();
-        self.scan_string(s)
+        let string = wrd.into();
+        self.scan_string(string)
     }
 
     fn spaces(&mut self, n: usize) {
@@ -620,7 +470,10 @@ impl Printer {
     }
 
     pub fn is_beginning_of_line(&self) -> bool {
-        self.last_token().is_eof() || self.last_token().is_hardbreak_tok()
+        match self.last_token() {
+            Some(last_token) => last_token.is_hardbreak_tok(),
+            None => true,
+        }
     }
 
     pub fn hardbreak_tok_offset(off: isize) -> Token {
diff --git a/compiler/rustc_ast_pretty/src/pp/ring.rs b/compiler/rustc_ast_pretty/src/pp/ring.rs
new file mode 100644
index 00000000000..8187394fe30
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pp/ring.rs
@@ -0,0 +1,77 @@
+use std::collections::VecDeque;
+use std::ops::{Index, IndexMut};
+
+/// A view onto a finite range of an infinitely long sequence of T.
+///
+/// The Ts are indexed 0..infinity. A RingBuffer begins as a view of elements
+/// 0..0 (i.e. nothing). The user of the RingBuffer advances its left and right
+/// position independently, although only in the positive direction, and only
+/// with left <= right at all times.
+///
+/// Holding a RingBuffer whose view is elements left..right gives the ability to
+/// use Index and IndexMut to access elements i in the infinitely long queue for
+/// which left <= i < right.
+pub struct RingBuffer<T> {
+    data: VecDeque<T>,
+    // Abstract index of data[0] in the infinitely sized queue.
+    offset: usize,
+}
+
+impl<T> RingBuffer<T> {
+    pub fn new() -> Self {
+        RingBuffer { data: VecDeque::new(), offset: 0 }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.data.is_empty()
+    }
+
+    pub fn push(&mut self, value: T) -> usize {
+        let index = self.offset + self.data.len();
+        self.data.push_back(value);
+        index
+    }
+
+    pub fn clear(&mut self) {
+        self.data.clear();
+    }
+
+    pub fn index_of_first(&self) -> usize {
+        self.offset
+    }
+
+    pub fn first(&self) -> Option<&T> {
+        self.data.front()
+    }
+
+    pub fn first_mut(&mut self) -> Option<&mut T> {
+        self.data.front_mut()
+    }
+
+    pub fn pop_first(&mut self) -> Option<T> {
+        let first = self.data.pop_front()?;
+        self.offset += 1;
+        Some(first)
+    }
+
+    pub fn last(&self) -> Option<&T> {
+        self.data.back()
+    }
+
+    pub fn last_mut(&mut self) -> Option<&mut T> {
+        self.data.back_mut()
+    }
+}
+
+impl<T> Index<usize> for RingBuffer<T> {
+    type Output = T;
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.data[index.checked_sub(self.offset).unwrap()]
+    }
+}
+
+impl<T> IndexMut<usize> for RingBuffer<T> {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        &mut self.data[index.checked_sub(self.offset).unwrap()]
+    }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index dab2e1f5ee1..1cbc3162d43 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1,15 +1,18 @@
+mod expr;
+mod item;
+
 use crate::pp::Breaks::{Consistent, Inconsistent};
 use crate::pp::{self, Breaks};
 
-use rustc_ast::attr;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::util::classify;
 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
-use rustc_ast::util::parser::{self, AssocOp, Fixity};
+use rustc_ast::util::parser;
 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs, ModKind};
+use rustc_ast::{attr, Term};
+use rustc_ast::{GenericArg, MacArgs};
 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -210,10 +213,6 @@ pub fn literal_to_string(lit: token::Lit) -> String {
     out
 }
 
-fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
-    format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
-}
-
 impl std::ops::Deref for State<'_> {
     type Target = pp::Printer;
     fn deref(&self) -> &Self::Target {
@@ -329,9 +328,9 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
             CommentStyle::BlankLine => {
                 // We need to do at least one, possibly two hardbreaks.
                 let twice = match self.last_token() {
-                    pp::Token::String(s) => ";" == s,
-                    pp::Token::Begin(_) => true,
-                    pp::Token::End => true,
+                    Some(pp::Token::String(s)) => ";" == s,
+                    Some(pp::Token::Begin(_)) => true,
+                    Some(pp::Token::End) => true,
                     _ => false,
                 };
                 if twice {
@@ -687,11 +686,15 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
     fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
         if !self.is_beginning_of_line() {
             self.break_offset(n, off)
-        } else if off != 0 && self.last_token().is_hardbreak_tok() {
-            // We do something pretty sketchy here: tuck the nonzero
-            // offset-adjustment we were going to deposit along with the
-            // break into the previous hardbreak.
-            self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
+        } else if off != 0 {
+            if let Some(last_token) = self.last_token_still_buffered() {
+                if last_token.is_hardbreak_tok() {
+                    // We do something pretty sketchy here: tuck the nonzero
+                    // offset-adjustment we were going to deposit along with the
+                    // break into the previous hardbreak.
+                    self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));
+                }
+            }
         }
     }
 
@@ -938,13 +941,6 @@ impl<'a> State<'a> {
         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
     }
 
-    crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
-        self.print_inner_attributes(attrs);
-        for item in &nmod.items {
-            self.print_foreign_item(item);
-        }
-    }
-
     pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
         if let Some(lt) = *lifetime {
             self.print_lifetime(lt);
@@ -952,18 +948,19 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
+    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
         self.print_ident(constraint.ident);
         constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
         self.space();
         match &constraint.kind {
-            ast::AssocTyConstraintKind::Equality { ty } => {
+            ast::AssocConstraintKind::Equality { term } => {
                 self.word_space("=");
-                self.print_type(ty);
-            }
-            ast::AssocTyConstraintKind::Bound { bounds } => {
-                self.print_type_bounds(":", &*bounds);
+                match term {
+                    Term::Ty(ty) => self.print_type(ty),
+                    Term::Const(c) => self.print_expr_anon_const(c),
+                }
             }
+            ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
         }
     }
 
@@ -1056,343 +1053,6 @@ impl<'a> State<'a> {
         self.end();
     }
 
-    crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
-        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
-        self.ann.pre(self, AnnNode::SubItem(id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(span.lo());
-        self.print_outer_attributes(attrs);
-        match kind {
-            ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
-            }
-            ast::ForeignItemKind::Static(ty, mutbl, body) => {
-                let def = ast::Defaultness::Final;
-                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
-            }
-            ast::ForeignItemKind::TyAlias(box ast::TyAlias {
-                defaultness,
-                generics,
-                bounds,
-                ty,
-            }) => {
-                self.print_associated_type(
-                    ident,
-                    generics,
-                    bounds,
-                    ty.as_deref(),
-                    vis,
-                    *defaultness,
-                );
-            }
-            ast::ForeignItemKind::MacCall(m) => {
-                self.print_mac(m);
-                if m.args.need_semicolon() {
-                    self.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(id))
-    }
-
-    fn print_item_const(
-        &mut self,
-        ident: Ident,
-        mutbl: Option<ast::Mutability>,
-        ty: &ast::Ty,
-        body: Option<&ast::Expr>,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-    ) {
-        self.head("");
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        let leading = match mutbl {
-            None => "const",
-            Some(ast::Mutability::Not) => "static",
-            Some(ast::Mutability::Mut) => "static mut",
-        };
-        self.word_space(leading);
-        self.print_ident(ident);
-        self.word_space(":");
-        self.print_type(ty);
-        if body.is_some() {
-            self.space();
-        }
-        self.end(); // end the head-ibox
-        if let Some(body) = body {
-            self.word_space("=");
-            self.print_expr(body);
-        }
-        self.word(";");
-        self.end(); // end the outer cbox
-    }
-
-    fn print_associated_type(
-        &mut self,
-        ident: Ident,
-        generics: &ast::Generics,
-        bounds: &ast::GenericBounds,
-        ty: Option<&ast::Ty>,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-    ) {
-        self.head("");
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        self.word_space("type");
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        self.print_type_bounds(":", bounds);
-        self.print_where_clause(&generics.where_clause);
-        if let Some(ty) = ty {
-            self.space();
-            self.word_space("=");
-            self.print_type(ty);
-        }
-        self.word(";");
-        self.end(); // end inner head-block
-        self.end(); // end outer head-block
-    }
-
-    /// Pretty-prints an item.
-    crate fn print_item(&mut self, item: &ast::Item) {
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(item.span.lo());
-        self.print_outer_attributes(&item.attrs);
-        self.ann.pre(self, AnnNode::Item(item));
-        match item.kind {
-            ast::ItemKind::ExternCrate(orig_name) => {
-                self.head(visibility_qualified(&item.vis, "extern crate"));
-                if let Some(orig_name) = orig_name {
-                    self.print_name(orig_name);
-                    self.space();
-                    self.word("as");
-                    self.space();
-                }
-                self.print_ident(item.ident);
-                self.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
-            }
-            ast::ItemKind::Use(ref tree) => {
-                self.head(visibility_qualified(&item.vis, "use"));
-                self.print_use_tree(tree);
-                self.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
-            }
-            ast::ItemKind::Static(ref ty, mutbl, ref body) => {
-                let def = ast::Defaultness::Final;
-                self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
-            }
-            ast::ItemKind::Const(def, ref ty, ref body) => {
-                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
-            }
-            ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
-                let body = body.as_deref();
-                self.print_fn_full(
-                    sig,
-                    item.ident,
-                    generics,
-                    &item.vis,
-                    defaultness,
-                    body,
-                    &item.attrs,
-                );
-            }
-            ast::ItemKind::Mod(unsafety, ref mod_kind) => {
-                self.head(Self::to_string(|s| {
-                    s.print_visibility(&item.vis);
-                    s.print_unsafety(unsafety);
-                    s.word("mod");
-                }));
-                self.print_ident(item.ident);
-
-                match mod_kind {
-                    ModKind::Loaded(items, ..) => {
-                        self.nbsp();
-                        self.bopen();
-                        self.print_inner_attributes(&item.attrs);
-                        for item in items {
-                            self.print_item(item);
-                        }
-                        let empty = item.attrs.is_empty() && items.is_empty();
-                        self.bclose(item.span, empty);
-                    }
-                    ModKind::Unloaded => {
-                        self.word(";");
-                        self.end(); // end inner head-block
-                        self.end(); // end outer head-block
-                    }
-                }
-            }
-            ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head(Self::to_string(|s| {
-                    s.print_unsafety(nmod.unsafety);
-                    s.word("extern");
-                }));
-                if let Some(abi) = nmod.abi {
-                    self.print_literal(&abi.as_lit());
-                    self.nbsp();
-                }
-                self.bopen();
-                self.print_foreign_mod(nmod, &item.attrs);
-                let empty = item.attrs.is_empty() && nmod.items.is_empty();
-                self.bclose(item.span, empty);
-            }
-            ast::ItemKind::GlobalAsm(ref asm) => {
-                self.head(visibility_qualified(&item.vis, "global_asm!"));
-                self.print_inline_asm(asm);
-                self.end();
-            }
-            ast::ItemKind::TyAlias(box ast::TyAlias {
-                defaultness,
-                ref generics,
-                ref bounds,
-                ref ty,
-            }) => {
-                let ty = ty.as_deref();
-                self.print_associated_type(
-                    item.ident,
-                    generics,
-                    bounds,
-                    ty,
-                    &item.vis,
-                    defaultness,
-                );
-            }
-            ast::ItemKind::Enum(ref enum_definition, ref params) => {
-                self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
-            }
-            ast::ItemKind::Struct(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "struct"));
-                self.print_struct(struct_def, generics, item.ident, item.span, true);
-            }
-            ast::ItemKind::Union(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "union"));
-                self.print_struct(struct_def, generics, item.ident, item.span, true);
-            }
-            ast::ItemKind::Impl(box ast::Impl {
-                unsafety,
-                polarity,
-                defaultness,
-                constness,
-                ref generics,
-                ref of_trait,
-                ref self_ty,
-                ref items,
-            }) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.print_defaultness(defaultness);
-                self.print_unsafety(unsafety);
-                self.word("impl");
-
-                if generics.params.is_empty() {
-                    self.nbsp();
-                } else {
-                    self.print_generic_params(&generics.params);
-                    self.space();
-                }
-
-                self.print_constness(constness);
-
-                if let ast::ImplPolarity::Negative(_) = polarity {
-                    self.word("!");
-                }
-
-                if let Some(ref t) = *of_trait {
-                    self.print_trait_ref(t);
-                    self.space();
-                    self.word_space("for");
-                }
-
-                self.print_type(self_ty);
-                self.print_where_clause(&generics.where_clause);
-
-                self.space();
-                self.bopen();
-                self.print_inner_attributes(&item.attrs);
-                for impl_item in items {
-                    self.print_assoc_item(impl_item);
-                }
-                let empty = item.attrs.is_empty() && items.is_empty();
-                self.bclose(item.span, empty);
-            }
-            ast::ItemKind::Trait(box ast::Trait {
-                is_auto,
-                unsafety,
-                ref generics,
-                ref bounds,
-                ref items,
-                ..
-            }) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.print_unsafety(unsafety);
-                self.print_is_auto(is_auto);
-                self.word_nbsp("trait");
-                self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b.clone());
-                    }
-                }
-                self.print_type_bounds(":", &real_bounds);
-                self.print_where_clause(&generics.where_clause);
-                self.word(" ");
-                self.bopen();
-                self.print_inner_attributes(&item.attrs);
-                for trait_item in items {
-                    self.print_assoc_item(trait_item);
-                }
-                let empty = item.attrs.is_empty() && items.is_empty();
-                self.bclose(item.span, empty);
-            }
-            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
-                self.head(visibility_qualified(&item.vis, "trait"));
-                self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                // FIXME(durka) this seems to be some quite outdated syntax
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b.clone());
-                    }
-                }
-                self.nbsp();
-                self.print_type_bounds("=", &real_bounds);
-                self.print_where_clause(&generics.where_clause);
-                self.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
-            }
-            ast::ItemKind::MacCall(ref mac) => {
-                self.print_mac(mac);
-                if mac.args.need_semicolon() {
-                    self.word(";");
-                }
-            }
-            ast::ItemKind::MacroDef(ref macro_def) => {
-                self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
-                    state.print_visibility(&item.vis)
-                });
-            }
-        }
-        self.ann.post(self, AnnNode::Item(item))
-    }
-
     fn print_trait_ref(&mut self, t: &ast::TraitRef) {
         self.print_path(&t.path, false, 0)
     }
@@ -1410,167 +1070,6 @@ impl<'a> State<'a> {
         self.print_trait_ref(&t.trait_ref)
     }
 
-    crate fn print_enum_def(
-        &mut self,
-        enum_definition: &ast::EnumDef,
-        generics: &ast::Generics,
-        ident: Ident,
-        span: rustc_span::Span,
-        visibility: &ast::Visibility,
-    ) {
-        self.head(visibility_qualified(visibility, "enum"));
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        self.print_where_clause(&generics.where_clause);
-        self.space();
-        self.print_variants(&enum_definition.variants, span)
-    }
-
-    crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
-        self.bopen();
-        for v in variants {
-            self.space_if_not_bol();
-            self.maybe_print_comment(v.span.lo());
-            self.print_outer_attributes(&v.attrs);
-            self.ibox(INDENT_UNIT);
-            self.print_variant(v);
-            self.word(",");
-            self.end();
-            self.maybe_print_trailing_comment(v.span, None);
-        }
-        let empty = variants.is_empty();
-        self.bclose(span, empty)
-    }
-
-    crate fn print_visibility(&mut self, vis: &ast::Visibility) {
-        match vis.kind {
-            ast::VisibilityKind::Public => self.word_nbsp("pub"),
-            ast::VisibilityKind::Crate(sugar) => match sugar {
-                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
-                ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
-            },
-            ast::VisibilityKind::Restricted { ref path, .. } => {
-                let path = Self::to_string(|s| s.print_path(path, false, 0));
-                if path == "self" || path == "super" {
-                    self.word_nbsp(format!("pub({})", path))
-                } else {
-                    self.word_nbsp(format!("pub(in {})", path))
-                }
-            }
-            ast::VisibilityKind::Inherited => {}
-        }
-    }
-
-    crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
-        if let ast::Defaultness::Default(_) = defaultness {
-            self.word_nbsp("default");
-        }
-    }
-
-    crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
-        self.nbsp();
-        self.bopen();
-
-        let empty = fields.is_empty();
-        if !empty {
-            self.hardbreak_if_not_bol();
-
-            for field in fields {
-                self.hardbreak_if_not_bol();
-                self.maybe_print_comment(field.span.lo());
-                self.print_outer_attributes(&field.attrs);
-                self.print_visibility(&field.vis);
-                self.print_ident(field.ident.unwrap());
-                self.word_nbsp(":");
-                self.print_type(&field.ty);
-                self.word(",");
-            }
-        }
-
-        self.bclose(span, empty);
-    }
-
-    crate fn print_struct(
-        &mut self,
-        struct_def: &ast::VariantData,
-        generics: &ast::Generics,
-        ident: Ident,
-        span: rustc_span::Span,
-        print_finalizer: bool,
-    ) {
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        match struct_def {
-            ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
-                if let ast::VariantData::Tuple(..) = struct_def {
-                    self.popen();
-                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
-                        s.maybe_print_comment(field.span.lo());
-                        s.print_outer_attributes(&field.attrs);
-                        s.print_visibility(&field.vis);
-                        s.print_type(&field.ty)
-                    });
-                    self.pclose();
-                }
-                self.print_where_clause(&generics.where_clause);
-                if print_finalizer {
-                    self.word(";");
-                }
-                self.end();
-                self.end(); // Close the outer-box.
-            }
-            ast::VariantData::Struct(ref fields, ..) => {
-                self.print_where_clause(&generics.where_clause);
-                self.print_record_struct_body(fields, span);
-            }
-        }
-    }
-
-    crate fn print_variant(&mut self, v: &ast::Variant) {
-        self.head("");
-        self.print_visibility(&v.vis);
-        let generics = ast::Generics::default();
-        self.print_struct(&v.data, &generics, v.ident, v.span, false);
-        if let Some(ref d) = v.disr_expr {
-            self.space();
-            self.word_space("=");
-            self.print_expr(&d.value)
-        }
-    }
-
-    crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
-        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
-        self.ann.pre(self, AnnNode::SubItem(id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(span.lo());
-        self.print_outer_attributes(attrs);
-        match kind {
-            ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
-            }
-            ast::AssocItemKind::Const(def, ty, body) => {
-                self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
-            }
-            ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
-                self.print_associated_type(
-                    ident,
-                    generics,
-                    bounds,
-                    ty.as_deref(),
-                    vis,
-                    *defaultness,
-                );
-            }
-            ast::AssocItemKind::MacCall(m) => {
-                self.print_mac(m);
-                if m.args.need_semicolon() {
-                    self.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(id))
-    }
-
     crate fn print_stmt(&mut self, st: &ast::Stmt) {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
@@ -1681,42 +1180,6 @@ impl<'a> State<'a> {
         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
     }
 
-    fn print_else(&mut self, els: Option<&ast::Expr>) {
-        if let Some(_else) = els {
-            match _else.kind {
-                // Another `else if` block.
-                ast::ExprKind::If(ref i, ref then, ref e) => {
-                    self.cbox(INDENT_UNIT - 1);
-                    self.ibox(0);
-                    self.word(" else if ");
-                    self.print_expr_as_cond(i);
-                    self.space();
-                    self.print_block(then);
-                    self.print_else(e.as_deref())
-                }
-                // Final `else` block.
-                ast::ExprKind::Block(ref b, _) => {
-                    self.cbox(INDENT_UNIT - 1);
-                    self.ibox(0);
-                    self.word(" else ");
-                    self.print_block(b)
-                }
-                // Constraints would be great here!
-                _ => {
-                    panic!("print_if saw if with weird alternative");
-                }
-            }
-        }
-    }
-
-    crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
-        self.head("if");
-        self.print_expr_as_cond(test);
-        self.space();
-        self.print_block(blk);
-        self.print_else(elseopt)
-    }
-
     crate fn print_mac(&mut self, m: &ast::MacCall) {
         self.print_mac_common(
             Some(MacHeader::Path(&m.path)),
@@ -1729,477 +1192,6 @@ impl<'a> State<'a> {
         );
     }
 
-    fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
-        self.popen();
-        self.commasep_exprs(Inconsistent, args);
-        self.pclose()
-    }
-
-    crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
-        self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
-    }
-
-    /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
-    /// `if cond { ... }`.
-    crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
-        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
-    }
-
-    // Does `expr` need parentheses when printed in a condition position?
-    //
-    // These cases need parens due to the parse error observed in #26461: `if return {}`
-    // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
-    fn cond_needs_par(expr: &ast::Expr) -> bool {
-        match expr.kind {
-            ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
-            _ => parser::contains_exterior_struct_lit(expr),
-        }
-    }
-
-    /// Prints `expr` or `(expr)` when `needs_par` holds.
-    fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
-        if needs_par {
-            self.popen();
-        }
-        self.print_expr(expr);
-        if needs_par {
-            self.pclose();
-        }
-    }
-
-    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
-        self.ibox(INDENT_UNIT);
-        self.word("[");
-        self.commasep_exprs(Inconsistent, exprs);
-        self.word("]");
-        self.end();
-    }
-
-    fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
-        self.ibox(INDENT_UNIT);
-        self.word("const");
-        self.print_expr(&expr.value);
-        self.end();
-    }
-
-    fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
-        self.ibox(INDENT_UNIT);
-        self.word("[");
-        self.print_expr(element);
-        self.word_space(";");
-        self.print_expr(&count.value);
-        self.word("]");
-        self.end();
-    }
-
-    fn print_expr_struct(
-        &mut self,
-        qself: &Option<ast::QSelf>,
-        path: &ast::Path,
-        fields: &[ast::ExprField],
-        rest: &ast::StructRest,
-    ) {
-        if let Some(qself) = qself {
-            self.print_qpath(path, qself, true);
-        } else {
-            self.print_path(path, true, 0);
-        }
-        self.word("{");
-        self.commasep_cmnt(
-            Consistent,
-            fields,
-            |s, field| {
-                s.print_outer_attributes(&field.attrs);
-                s.ibox(INDENT_UNIT);
-                if !field.is_shorthand {
-                    s.print_ident(field.ident);
-                    s.word_space(":");
-                }
-                s.print_expr(&field.expr);
-                s.end();
-            },
-            |f| f.span,
-        );
-        match rest {
-            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
-                self.ibox(INDENT_UNIT);
-                if !fields.is_empty() {
-                    self.word(",");
-                    self.space();
-                }
-                self.word("..");
-                if let ast::StructRest::Base(ref expr) = *rest {
-                    self.print_expr(expr);
-                }
-                self.end();
-            }
-            ast::StructRest::None if !fields.is_empty() => self.word(","),
-            _ => {}
-        }
-        self.word("}");
-    }
-
-    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
-        self.popen();
-        self.commasep_exprs(Inconsistent, exprs);
-        if exprs.len() == 1 {
-            self.word(",");
-        }
-        self.pclose()
-    }
-
-    fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
-        let prec = match func.kind {
-            ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
-            _ => parser::PREC_POSTFIX,
-        };
-
-        self.print_expr_maybe_paren(func, prec);
-        self.print_call_post(args)
-    }
-
-    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
-        let base_args = &args[1..];
-        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
-        self.word(".");
-        self.print_ident(segment.ident);
-        if let Some(ref args) = segment.args {
-            self.print_generic_args(args, true);
-        }
-        self.print_call_post(base_args)
-    }
-
-    fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
-        let assoc_op = AssocOp::from_ast_binop(op.node);
-        let prec = assoc_op.precedence() as i8;
-        let fixity = assoc_op.fixity();
-
-        let (left_prec, right_prec) = match fixity {
-            Fixity::Left => (prec, prec + 1),
-            Fixity::Right => (prec + 1, prec),
-            Fixity::None => (prec + 1, prec + 1),
-        };
-
-        let left_prec = match (&lhs.kind, op.node) {
-            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
-            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
-            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
-            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
-                parser::PREC_FORCE_PAREN
-            }
-            // We are given `(let _ = a) OP b`.
-            //
-            // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
-            //   as the parser will interpret this as `(let _ = a) OP b`.
-            //
-            // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
-            //   parens are required since the parser would interpret `let a = b < c` as
-            //   `let a = (b < c)`. To achieve this, we force parens.
-            (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
-                parser::PREC_FORCE_PAREN
-            }
-            _ => left_prec,
-        };
-
-        self.print_expr_maybe_paren(lhs, left_prec);
-        self.space();
-        self.word_space(op.node.to_string());
-        self.print_expr_maybe_paren(rhs, right_prec)
-    }
-
-    fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
-        self.word(ast::UnOp::to_string(op));
-        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
-    }
-
-    fn print_expr_addr_of(
-        &mut self,
-        kind: ast::BorrowKind,
-        mutability: ast::Mutability,
-        expr: &ast::Expr,
-    ) {
-        self.word("&");
-        match kind {
-            ast::BorrowKind::Ref => self.print_mutability(mutability, false),
-            ast::BorrowKind::Raw => {
-                self.word_nbsp("raw");
-                self.print_mutability(mutability, true);
-            }
-        }
-        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
-    }
-
-    pub fn print_expr(&mut self, expr: &ast::Expr) {
-        self.print_expr_outer_attr_style(expr, true)
-    }
-
-    fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
-        self.maybe_print_comment(expr.span.lo());
-
-        let attrs = &expr.attrs;
-        if is_inline {
-            self.print_outer_attributes_inline(attrs);
-        } else {
-            self.print_outer_attributes(attrs);
-        }
-
-        self.ibox(INDENT_UNIT);
-        self.ann.pre(self, AnnNode::Expr(expr));
-        match expr.kind {
-            ast::ExprKind::Box(ref expr) => {
-                self.word_space("box");
-                self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
-            }
-            ast::ExprKind::Array(ref exprs) => {
-                self.print_expr_vec(exprs);
-            }
-            ast::ExprKind::ConstBlock(ref anon_const) => {
-                self.print_expr_anon_const(anon_const);
-            }
-            ast::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(element, count);
-            }
-            ast::ExprKind::Struct(ref se) => {
-                self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
-            }
-            ast::ExprKind::Tup(ref exprs) => {
-                self.print_expr_tup(exprs);
-            }
-            ast::ExprKind::Call(ref func, ref args) => {
-                self.print_expr_call(func, &args);
-            }
-            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
-                self.print_expr_method_call(segment, &args);
-            }
-            ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
-                self.print_expr_binary(op, lhs, rhs);
-            }
-            ast::ExprKind::Unary(op, ref expr) => {
-                self.print_expr_unary(op, expr);
-            }
-            ast::ExprKind::AddrOf(k, m, ref expr) => {
-                self.print_expr_addr_of(k, m, expr);
-            }
-            ast::ExprKind::Lit(ref lit) => {
-                self.print_literal(lit);
-            }
-            ast::ExprKind::Cast(ref expr, ref ty) => {
-                let prec = AssocOp::As.precedence() as i8;
-                self.print_expr_maybe_paren(expr, prec);
-                self.space();
-                self.word_space("as");
-                self.print_type(ty);
-            }
-            ast::ExprKind::Type(ref expr, ref ty) => {
-                let prec = AssocOp::Colon.precedence() as i8;
-                self.print_expr_maybe_paren(expr, prec);
-                self.word_space(":");
-                self.print_type(ty);
-            }
-            ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
-                self.print_let(pat, scrutinee);
-            }
-            ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                self.print_if(test, blk, elseopt.as_deref())
-            }
-            ast::ExprKind::While(ref test, ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("while");
-                self.print_expr_as_cond(test);
-                self.space();
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("for");
-                self.print_pat(pat);
-                self.space();
-                self.word_space("in");
-                self.print_expr_as_cond(iter);
-                self.space();
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Loop(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("loop");
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Match(ref expr, ref arms) => {
-                self.cbox(INDENT_UNIT);
-                self.ibox(INDENT_UNIT);
-                self.word_nbsp("match");
-                self.print_expr_as_cond(expr);
-                self.space();
-                self.bopen();
-                self.print_inner_attributes_no_trailing_hardbreak(attrs);
-                for arm in arms {
-                    self.print_arm(arm);
-                }
-                let empty = attrs.is_empty() && arms.is_empty();
-                self.bclose(expr.span, empty);
-            }
-            ast::ExprKind::Closure(
-                capture_clause,
-                asyncness,
-                movability,
-                ref decl,
-                ref body,
-                _,
-            ) => {
-                self.print_movability(movability);
-                self.print_asyncness(asyncness);
-                self.print_capture_clause(capture_clause);
-
-                self.print_fn_params_and_ret(decl, true);
-                self.space();
-                self.print_expr(body);
-                self.end(); // need to close a box
-
-                // a box will be closed by print_expr, but we didn't want an overall
-                // wrapper so we closed the corresponding opening. so create an
-                // empty box to satisfy the close.
-                self.ibox(0);
-            }
-            ast::ExprKind::Block(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                // containing cbox, will be closed by print-block at }
-                self.cbox(INDENT_UNIT);
-                // head-box, will be closed by print-block after {
-                self.ibox(0);
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Async(capture_clause, _, ref blk) => {
-                self.word_nbsp("async");
-                self.print_capture_clause(capture_clause);
-                // cbox/ibox in analogy to the `ExprKind::Block` arm above
-                self.cbox(INDENT_UNIT);
-                self.ibox(0);
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Await(ref expr) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.word(".await");
-            }
-            ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
-                let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(lhs, prec + 1);
-                self.space();
-                self.word_space("=");
-                self.print_expr_maybe_paren(rhs, prec);
-            }
-            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(lhs, prec + 1);
-                self.space();
-                self.word(op.node.to_string());
-                self.word_space("=");
-                self.print_expr_maybe_paren(rhs, prec);
-            }
-            ast::ExprKind::Field(ref expr, ident) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.word(".");
-                self.print_ident(ident);
-            }
-            ast::ExprKind::Index(ref expr, ref index) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.word("[");
-                self.print_expr(index);
-                self.word("]");
-            }
-            ast::ExprKind::Range(ref start, ref end, limits) => {
-                // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
-                // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
-                // Here we use a fake precedence value so that any child with lower precedence than
-                // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
-                let fake_prec = AssocOp::LOr.precedence() as i8;
-                if let Some(ref e) = *start {
-                    self.print_expr_maybe_paren(e, fake_prec);
-                }
-                if limits == ast::RangeLimits::HalfOpen {
-                    self.word("..");
-                } else {
-                    self.word("..=");
-                }
-                if let Some(ref e) = *end {
-                    self.print_expr_maybe_paren(e, fake_prec);
-                }
-            }
-            ast::ExprKind::Underscore => self.word("_"),
-            ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
-            ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
-            ast::ExprKind::Break(opt_label, ref opt_expr) => {
-                self.word("break");
-                if let Some(label) = opt_label {
-                    self.space();
-                    self.print_ident(label.ident);
-                }
-                if let Some(ref expr) = *opt_expr {
-                    self.space();
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::Continue(opt_label) => {
-                self.word("continue");
-                if let Some(label) = opt_label {
-                    self.space();
-                    self.print_ident(label.ident);
-                }
-            }
-            ast::ExprKind::Ret(ref result) => {
-                self.word("return");
-                if let Some(ref expr) = *result {
-                    self.word(" ");
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::InlineAsm(ref a) => {
-                self.word("asm!");
-                self.print_inline_asm(a);
-            }
-            ast::ExprKind::MacCall(ref m) => self.print_mac(m),
-            ast::ExprKind::Paren(ref e) => {
-                self.popen();
-                self.print_expr(e);
-                self.pclose();
-            }
-            ast::ExprKind::Yield(ref e) => {
-                self.word("yield");
-
-                if let Some(ref expr) = *e {
-                    self.space();
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::Try(ref e) => {
-                self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
-                self.word("?")
-            }
-            ast::ExprKind::TryBlock(ref blk) => {
-                self.head("try");
-                self.print_block_with_attrs(blk, attrs)
-            }
-            ast::ExprKind::Err => {
-                self.popen();
-                self.word("/*ERROR*/");
-                self.pclose()
-            }
-        }
-        self.ann.post(self, AnnNode::Expr(expr));
-        self.end();
-    }
-
     fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
         enum AsmArg<'a> {
             Template(String),
@@ -2495,48 +1487,6 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::Pat(pat))
     }
 
-    fn print_arm(&mut self, arm: &ast::Arm) {
-        // Note, I have no idea why this check is necessary, but here it is.
-        if arm.attrs.is_empty() {
-            self.space();
-        }
-        self.cbox(INDENT_UNIT);
-        self.ibox(0);
-        self.maybe_print_comment(arm.pat.span.lo());
-        self.print_outer_attributes(&arm.attrs);
-        self.print_pat(&arm.pat);
-        self.space();
-        if let Some(ref e) = arm.guard {
-            self.word_space("if");
-            self.print_expr(e);
-            self.space();
-        }
-        self.word_space("=>");
-
-        match arm.body.kind {
-            ast::ExprKind::Block(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-
-                // The block will close the pattern's ibox.
-                self.print_block_unclosed_indent(blk);
-
-                // If it is a user-provided unsafe block, print a comma after it.
-                if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
-                    self.word(",");
-                }
-            }
-            _ => {
-                self.end(); // Close the ibox for the pattern.
-                self.print_expr(&arm.body);
-                self.word(",");
-            }
-        }
-        self.end(); // Close enclosing cbox.
-    }
-
     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
         match explicit_self.node {
             SelfKind::Value(m) => {
@@ -2558,75 +1508,12 @@ impl<'a> State<'a> {
         }
     }
 
-    fn print_fn_full(
-        &mut self,
-        sig: &ast::FnSig,
-        name: Ident,
-        generics: &ast::Generics,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-        body: Option<&ast::Block>,
-        attrs: &[ast::Attribute],
-    ) {
-        if body.is_some() {
-            self.head("");
-        }
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        self.print_fn(&sig.decl, sig.header, Some(name), generics);
-        if let Some(body) = body {
-            self.nbsp();
-            self.print_block_with_attrs(body, attrs);
-        } else {
-            self.word(";");
-        }
-    }
-
-    crate fn print_fn(
-        &mut self,
-        decl: &ast::FnDecl,
-        header: ast::FnHeader,
-        name: Option<Ident>,
-        generics: &ast::Generics,
-    ) {
-        self.print_fn_header_info(header);
-        if let Some(name) = name {
-            self.nbsp();
-            self.print_ident(name);
-        }
-        self.print_generic_params(&generics.params);
-        self.print_fn_params_and_ret(decl, false);
-        self.print_where_clause(&generics.where_clause)
-    }
-
-    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
-        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
-        self.word(open);
-        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
-        self.word(close);
-        self.print_fn_ret_ty(&decl.output)
-    }
-
-    crate fn print_movability(&mut self, movability: ast::Movability) {
-        match movability {
-            ast::Movability::Static => self.word_space("static"),
-            ast::Movability::Movable => {}
-        }
-    }
-
     crate fn print_asyncness(&mut self, asyncness: ast::Async) {
         if asyncness.is_async() {
             self.word_nbsp("async");
         }
     }
 
-    crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
-        match capture_clause {
-            ast::CaptureBy::Value => self.word_space("move"),
-            ast::CaptureBy::Ref => {}
-        }
-    }
-
     pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
         if !bounds.is_empty() {
             self.word(prefix);
@@ -2721,83 +1608,6 @@ impl<'a> State<'a> {
         self.word(">");
     }
 
-    crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
-        if where_clause.predicates.is_empty() && !where_clause.has_where_token {
-            return;
-        }
-
-        self.space();
-        self.word_space("where");
-
-        for (i, predicate) in where_clause.predicates.iter().enumerate() {
-            if i != 0 {
-                self.word_space(",");
-            }
-
-            self.print_where_predicate(predicate);
-        }
-    }
-
-    pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
-        match predicate {
-            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
-                bound_generic_params,
-                bounded_ty,
-                bounds,
-                ..
-            }) => {
-                self.print_formal_generic_params(bound_generic_params);
-                self.print_type(bounded_ty);
-                self.print_type_bounds(":", bounds);
-            }
-            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
-                lifetime,
-                bounds,
-                ..
-            }) => {
-                self.print_lifetime_bounds(*lifetime, bounds);
-            }
-            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
-                self.print_type(lhs_ty);
-                self.space();
-                self.word_space("=");
-                self.print_type(rhs_ty);
-            }
-        }
-    }
-
-    crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
-        match tree.kind {
-            ast::UseTreeKind::Simple(rename, ..) => {
-                self.print_path(&tree.prefix, false, 0);
-                if let Some(rename) = rename {
-                    self.space();
-                    self.word_space("as");
-                    self.print_ident(rename);
-                }
-            }
-            ast::UseTreeKind::Glob => {
-                if !tree.prefix.segments.is_empty() {
-                    self.print_path(&tree.prefix, false, 0);
-                    self.word("::");
-                }
-                self.word("*");
-            }
-            ast::UseTreeKind::Nested(ref items) => {
-                if tree.prefix.segments.is_empty() {
-                    self.word("{");
-                } else {
-                    self.print_path(&tree.prefix, false, 0);
-                    self.word("::{");
-                }
-                self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
-                    this.print_use_tree(tree)
-                });
-                self.word("}");
-            }
-        }
-    }
-
     pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
         match mutbl {
             ast::Mutability::Mut => self.word_nbsp("mut"),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
new file mode 100644
index 00000000000..956200d60f5
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -0,0 +1,571 @@
+use crate::pp::Breaks::{Consistent, Inconsistent};
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+
+use rustc_ast::ptr::P;
+use rustc_ast::util::parser::{self, AssocOp, Fixity};
+use rustc_ast::{self as ast, BlockCheckMode};
+
+impl<'a> State<'a> {
+    fn print_else(&mut self, els: Option<&ast::Expr>) {
+        if let Some(_else) = els {
+            match _else.kind {
+                // Another `else if` block.
+                ast::ExprKind::If(ref i, ref then, ref e) => {
+                    self.cbox(INDENT_UNIT - 1);
+                    self.ibox(0);
+                    self.word(" else if ");
+                    self.print_expr_as_cond(i);
+                    self.space();
+                    self.print_block(then);
+                    self.print_else(e.as_deref())
+                }
+                // Final `else` block.
+                ast::ExprKind::Block(ref b, _) => {
+                    self.cbox(INDENT_UNIT - 1);
+                    self.ibox(0);
+                    self.word(" else ");
+                    self.print_block(b)
+                }
+                // Constraints would be great here!
+                _ => {
+                    panic!("print_if saw if with weird alternative");
+                }
+            }
+        }
+    }
+
+    fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
+        self.head("if");
+        self.print_expr_as_cond(test);
+        self.space();
+        self.print_block(blk);
+        self.print_else(elseopt)
+    }
+
+    fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
+        self.popen();
+        self.commasep_exprs(Inconsistent, args);
+        self.pclose()
+    }
+
+    fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
+        self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
+    }
+
+    /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
+    /// `if cond { ... }`.
+    fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
+        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+    }
+
+    // Does `expr` need parentheses when printed in a condition position?
+    //
+    // These cases need parens due to the parse error observed in #26461: `if return {}`
+    // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
+    pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
+        match expr.kind {
+            ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
+            _ => parser::contains_exterior_struct_lit(expr),
+        }
+    }
+
+    /// Prints `expr` or `(expr)` when `needs_par` holds.
+    pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
+        if needs_par {
+            self.popen();
+        }
+        self.print_expr(expr);
+        if needs_par {
+            self.pclose();
+        }
+    }
+
+    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
+        self.ibox(INDENT_UNIT);
+        self.word("[");
+        self.commasep_exprs(Inconsistent, exprs);
+        self.word("]");
+        self.end();
+    }
+
+    pub(super) fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
+        self.ibox(INDENT_UNIT);
+        self.word("const");
+        self.print_expr(&expr.value);
+        self.end();
+    }
+
+    fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
+        self.ibox(INDENT_UNIT);
+        self.word("[");
+        self.print_expr(element);
+        self.word_space(";");
+        self.print_expr(&count.value);
+        self.word("]");
+        self.end();
+    }
+
+    fn print_expr_struct(
+        &mut self,
+        qself: &Option<ast::QSelf>,
+        path: &ast::Path,
+        fields: &[ast::ExprField],
+        rest: &ast::StructRest,
+    ) {
+        if let Some(qself) = qself {
+            self.print_qpath(path, qself, true);
+        } else {
+            self.print_path(path, true, 0);
+        }
+        self.word("{");
+        self.commasep_cmnt(
+            Consistent,
+            fields,
+            |s, field| {
+                s.print_outer_attributes(&field.attrs);
+                s.ibox(INDENT_UNIT);
+                if !field.is_shorthand {
+                    s.print_ident(field.ident);
+                    s.word_space(":");
+                }
+                s.print_expr(&field.expr);
+                s.end();
+            },
+            |f| f.span,
+        );
+        match rest {
+            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
+                self.ibox(INDENT_UNIT);
+                if !fields.is_empty() {
+                    self.word(",");
+                    self.space();
+                }
+                self.word("..");
+                if let ast::StructRest::Base(ref expr) = *rest {
+                    self.print_expr(expr);
+                }
+                self.end();
+            }
+            ast::StructRest::None if !fields.is_empty() => self.word(","),
+            _ => {}
+        }
+        self.word("}");
+    }
+
+    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
+        self.popen();
+        self.commasep_exprs(Inconsistent, exprs);
+        if exprs.len() == 1 {
+            self.word(",");
+        }
+        self.pclose()
+    }
+
+    fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
+        let prec = match func.kind {
+            ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
+            _ => parser::PREC_POSTFIX,
+        };
+
+        self.print_expr_maybe_paren(func, prec);
+        self.print_call_post(args)
+    }
+
+    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
+        let base_args = &args[1..];
+        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+        self.word(".");
+        self.print_ident(segment.ident);
+        if let Some(ref args) = segment.args {
+            self.print_generic_args(args, true);
+        }
+        self.print_call_post(base_args)
+    }
+
+    fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
+        let assoc_op = AssocOp::from_ast_binop(op.node);
+        let prec = assoc_op.precedence() as i8;
+        let fixity = assoc_op.fixity();
+
+        let (left_prec, right_prec) = match fixity {
+            Fixity::Left => (prec, prec + 1),
+            Fixity::Right => (prec + 1, prec),
+            Fixity::None => (prec + 1, prec + 1),
+        };
+
+        let left_prec = match (&lhs.kind, op.node) {
+            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
+            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
+            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
+            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
+                parser::PREC_FORCE_PAREN
+            }
+            // We are given `(let _ = a) OP b`.
+            //
+            // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
+            //   as the parser will interpret this as `(let _ = a) OP b`.
+            //
+            // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
+            //   parens are required since the parser would interpret `let a = b < c` as
+            //   `let a = (b < c)`. To achieve this, we force parens.
+            (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
+                parser::PREC_FORCE_PAREN
+            }
+            _ => left_prec,
+        };
+
+        self.print_expr_maybe_paren(lhs, left_prec);
+        self.space();
+        self.word_space(op.node.to_string());
+        self.print_expr_maybe_paren(rhs, right_prec)
+    }
+
+    fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
+        self.word(ast::UnOp::to_string(op));
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+    }
+
+    fn print_expr_addr_of(
+        &mut self,
+        kind: ast::BorrowKind,
+        mutability: ast::Mutability,
+        expr: &ast::Expr,
+    ) {
+        self.word("&");
+        match kind {
+            ast::BorrowKind::Ref => self.print_mutability(mutability, false),
+            ast::BorrowKind::Raw => {
+                self.word_nbsp("raw");
+                self.print_mutability(mutability, true);
+            }
+        }
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+    }
+
+    pub fn print_expr(&mut self, expr: &ast::Expr) {
+        self.print_expr_outer_attr_style(expr, true)
+    }
+
+    pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
+        self.maybe_print_comment(expr.span.lo());
+
+        let attrs = &expr.attrs;
+        if is_inline {
+            self.print_outer_attributes_inline(attrs);
+        } else {
+            self.print_outer_attributes(attrs);
+        }
+
+        self.ibox(INDENT_UNIT);
+        self.ann.pre(self, AnnNode::Expr(expr));
+        match expr.kind {
+            ast::ExprKind::Box(ref expr) => {
+                self.word_space("box");
+                self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
+            }
+            ast::ExprKind::Array(ref exprs) => {
+                self.print_expr_vec(exprs);
+            }
+            ast::ExprKind::ConstBlock(ref anon_const) => {
+                self.print_expr_anon_const(anon_const);
+            }
+            ast::ExprKind::Repeat(ref element, ref count) => {
+                self.print_expr_repeat(element, count);
+            }
+            ast::ExprKind::Struct(ref se) => {
+                self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
+            }
+            ast::ExprKind::Tup(ref exprs) => {
+                self.print_expr_tup(exprs);
+            }
+            ast::ExprKind::Call(ref func, ref args) => {
+                self.print_expr_call(func, &args);
+            }
+            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
+                self.print_expr_method_call(segment, &args);
+            }
+            ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
+                self.print_expr_binary(op, lhs, rhs);
+            }
+            ast::ExprKind::Unary(op, ref expr) => {
+                self.print_expr_unary(op, expr);
+            }
+            ast::ExprKind::AddrOf(k, m, ref expr) => {
+                self.print_expr_addr_of(k, m, expr);
+            }
+            ast::ExprKind::Lit(ref lit) => {
+                self.print_literal(lit);
+            }
+            ast::ExprKind::Cast(ref expr, ref ty) => {
+                let prec = AssocOp::As.precedence() as i8;
+                self.print_expr_maybe_paren(expr, prec);
+                self.space();
+                self.word_space("as");
+                self.print_type(ty);
+            }
+            ast::ExprKind::Type(ref expr, ref ty) => {
+                let prec = AssocOp::Colon.precedence() as i8;
+                self.print_expr_maybe_paren(expr, prec);
+                self.word_space(":");
+                self.print_type(ty);
+            }
+            ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
+                self.print_let(pat, scrutinee);
+            }
+            ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
+                self.print_if(test, blk, elseopt.as_deref())
+            }
+            ast::ExprKind::While(ref test, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("while");
+                self.print_expr_as_cond(test);
+                self.space();
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("for");
+                self.print_pat(pat);
+                self.space();
+                self.word_space("in");
+                self.print_expr_as_cond(iter);
+                self.space();
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Loop(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("loop");
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Match(ref expr, ref arms) => {
+                self.cbox(INDENT_UNIT);
+                self.ibox(INDENT_UNIT);
+                self.word_nbsp("match");
+                self.print_expr_as_cond(expr);
+                self.space();
+                self.bopen();
+                self.print_inner_attributes_no_trailing_hardbreak(attrs);
+                for arm in arms {
+                    self.print_arm(arm);
+                }
+                let empty = attrs.is_empty() && arms.is_empty();
+                self.bclose(expr.span, empty);
+            }
+            ast::ExprKind::Closure(
+                capture_clause,
+                asyncness,
+                movability,
+                ref decl,
+                ref body,
+                _,
+            ) => {
+                self.print_movability(movability);
+                self.print_asyncness(asyncness);
+                self.print_capture_clause(capture_clause);
+
+                self.print_fn_params_and_ret(decl, true);
+                self.space();
+                self.print_expr(body);
+                self.end(); // need to close a box
+
+                // a box will be closed by print_expr, but we didn't want an overall
+                // wrapper so we closed the corresponding opening. so create an
+                // empty box to satisfy the close.
+                self.ibox(0);
+            }
+            ast::ExprKind::Block(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                // containing cbox, will be closed by print-block at }
+                self.cbox(INDENT_UNIT);
+                // head-box, will be closed by print-block after {
+                self.ibox(0);
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Async(capture_clause, _, ref blk) => {
+                self.word_nbsp("async");
+                self.print_capture_clause(capture_clause);
+                // cbox/ibox in analogy to the `ExprKind::Block` arm above
+                self.cbox(INDENT_UNIT);
+                self.ibox(0);
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Await(ref expr) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.word(".await");
+            }
+            ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
+                let prec = AssocOp::Assign.precedence() as i8;
+                self.print_expr_maybe_paren(lhs, prec + 1);
+                self.space();
+                self.word_space("=");
+                self.print_expr_maybe_paren(rhs, prec);
+            }
+            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+                let prec = AssocOp::Assign.precedence() as i8;
+                self.print_expr_maybe_paren(lhs, prec + 1);
+                self.space();
+                self.word(op.node.to_string());
+                self.word_space("=");
+                self.print_expr_maybe_paren(rhs, prec);
+            }
+            ast::ExprKind::Field(ref expr, ident) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.word(".");
+                self.print_ident(ident);
+            }
+            ast::ExprKind::Index(ref expr, ref index) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.word("[");
+                self.print_expr(index);
+                self.word("]");
+            }
+            ast::ExprKind::Range(ref start, ref end, limits) => {
+                // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
+                // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
+                // Here we use a fake precedence value so that any child with lower precedence than
+                // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
+                let fake_prec = AssocOp::LOr.precedence() as i8;
+                if let Some(ref e) = *start {
+                    self.print_expr_maybe_paren(e, fake_prec);
+                }
+                if limits == ast::RangeLimits::HalfOpen {
+                    self.word("..");
+                } else {
+                    self.word("..=");
+                }
+                if let Some(ref e) = *end {
+                    self.print_expr_maybe_paren(e, fake_prec);
+                }
+            }
+            ast::ExprKind::Underscore => self.word("_"),
+            ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
+            ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
+            ast::ExprKind::Break(opt_label, ref opt_expr) => {
+                self.word("break");
+                if let Some(label) = opt_label {
+                    self.space();
+                    self.print_ident(label.ident);
+                }
+                if let Some(ref expr) = *opt_expr {
+                    self.space();
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::Continue(opt_label) => {
+                self.word("continue");
+                if let Some(label) = opt_label {
+                    self.space();
+                    self.print_ident(label.ident);
+                }
+            }
+            ast::ExprKind::Ret(ref result) => {
+                self.word("return");
+                if let Some(ref expr) = *result {
+                    self.word(" ");
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::InlineAsm(ref a) => {
+                self.word("asm!");
+                self.print_inline_asm(a);
+            }
+            ast::ExprKind::MacCall(ref m) => self.print_mac(m),
+            ast::ExprKind::Paren(ref e) => {
+                self.popen();
+                self.print_expr(e);
+                self.pclose();
+            }
+            ast::ExprKind::Yield(ref e) => {
+                self.word("yield");
+
+                if let Some(ref expr) = *e {
+                    self.space();
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::Try(ref e) => {
+                self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
+                self.word("?")
+            }
+            ast::ExprKind::TryBlock(ref blk) => {
+                self.head("try");
+                self.print_block_with_attrs(blk, attrs)
+            }
+            ast::ExprKind::Err => {
+                self.popen();
+                self.word("/*ERROR*/");
+                self.pclose()
+            }
+        }
+        self.ann.post(self, AnnNode::Expr(expr));
+        self.end();
+    }
+
+    fn print_arm(&mut self, arm: &ast::Arm) {
+        // Note, I have no idea why this check is necessary, but here it is.
+        if arm.attrs.is_empty() {
+            self.space();
+        }
+        self.cbox(INDENT_UNIT);
+        self.ibox(0);
+        self.maybe_print_comment(arm.pat.span.lo());
+        self.print_outer_attributes(&arm.attrs);
+        self.print_pat(&arm.pat);
+        self.space();
+        if let Some(ref e) = arm.guard {
+            self.word_space("if");
+            self.print_expr(e);
+            self.space();
+        }
+        self.word_space("=>");
+
+        match arm.body.kind {
+            ast::ExprKind::Block(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+
+                // The block will close the pattern's ibox.
+                self.print_block_unclosed_indent(blk);
+
+                // If it is a user-provided unsafe block, print a comma after it.
+                if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+                    self.word(",");
+                }
+            }
+            _ => {
+                self.end(); // Close the ibox for the pattern.
+                self.print_expr(&arm.body);
+                self.word(",");
+            }
+        }
+        self.end(); // Close enclosing cbox.
+    }
+
+    fn print_movability(&mut self, movability: ast::Movability) {
+        match movability {
+            ast::Movability::Static => self.word_space("static"),
+            ast::Movability::Movable => {}
+        }
+    }
+
+    fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
+        match capture_clause {
+            ast::CaptureBy::Value => self.word_space("move"),
+            ast::CaptureBy::Ref => {}
+        }
+    }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
new file mode 100644
index 00000000000..c756b946b1e
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -0,0 +1,644 @@
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+
+use rustc_ast as ast;
+use rustc_ast::GenericBound;
+use rustc_ast::ModKind;
+use rustc_span::symbol::Ident;
+
+fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
+    format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
+}
+
+impl<'a> State<'a> {
+    fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
+        self.print_inner_attributes(attrs);
+        for item in &nmod.items {
+            self.print_foreign_item(item);
+        }
+    }
+
+    fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+        self.ann.pre(self, AnnNode::SubItem(id));
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(span.lo());
+        self.print_outer_attributes(attrs);
+        match kind {
+            ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            }
+            ast::ForeignItemKind::Static(ty, mutbl, body) => {
+                let def = ast::Defaultness::Final;
+                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
+            }
+            ast::ForeignItemKind::TyAlias(box ast::TyAlias {
+                defaultness,
+                generics,
+                bounds,
+                ty,
+            }) => {
+                self.print_associated_type(
+                    ident,
+                    generics,
+                    bounds,
+                    ty.as_deref(),
+                    vis,
+                    *defaultness,
+                );
+            }
+            ast::ForeignItemKind::MacCall(m) => {
+                self.print_mac(m);
+                if m.args.need_semicolon() {
+                    self.word(";");
+                }
+            }
+        }
+        self.ann.post(self, AnnNode::SubItem(id))
+    }
+
+    fn print_item_const(
+        &mut self,
+        ident: Ident,
+        mutbl: Option<ast::Mutability>,
+        ty: &ast::Ty,
+        body: Option<&ast::Expr>,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+    ) {
+        self.head("");
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        let leading = match mutbl {
+            None => "const",
+            Some(ast::Mutability::Not) => "static",
+            Some(ast::Mutability::Mut) => "static mut",
+        };
+        self.word_space(leading);
+        self.print_ident(ident);
+        self.word_space(":");
+        self.print_type(ty);
+        if body.is_some() {
+            self.space();
+        }
+        self.end(); // end the head-ibox
+        if let Some(body) = body {
+            self.word_space("=");
+            self.print_expr(body);
+        }
+        self.word(";");
+        self.end(); // end the outer cbox
+    }
+
+    fn print_associated_type(
+        &mut self,
+        ident: Ident,
+        generics: &ast::Generics,
+        bounds: &ast::GenericBounds,
+        ty: Option<&ast::Ty>,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+    ) {
+        self.head("");
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        self.word_space("type");
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        self.print_type_bounds(":", bounds);
+        self.print_where_clause(&generics.where_clause);
+        if let Some(ty) = ty {
+            self.space();
+            self.word_space("=");
+            self.print_type(ty);
+        }
+        self.word(";");
+        self.end(); // end inner head-block
+        self.end(); // end outer head-block
+    }
+
+    /// Pretty-prints an item.
+    crate fn print_item(&mut self, item: &ast::Item) {
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(item.span.lo());
+        self.print_outer_attributes(&item.attrs);
+        self.ann.pre(self, AnnNode::Item(item));
+        match item.kind {
+            ast::ItemKind::ExternCrate(orig_name) => {
+                self.head(visibility_qualified(&item.vis, "extern crate"));
+                if let Some(orig_name) = orig_name {
+                    self.print_name(orig_name);
+                    self.space();
+                    self.word("as");
+                    self.space();
+                }
+                self.print_ident(item.ident);
+                self.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::Use(ref tree) => {
+                self.head(visibility_qualified(&item.vis, "use"));
+                self.print_use_tree(tree);
+                self.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::Static(ref ty, mutbl, ref body) => {
+                let def = ast::Defaultness::Final;
+                self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
+            }
+            ast::ItemKind::Const(def, ref ty, ref body) => {
+                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
+            }
+            ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
+                let body = body.as_deref();
+                self.print_fn_full(
+                    sig,
+                    item.ident,
+                    generics,
+                    &item.vis,
+                    defaultness,
+                    body,
+                    &item.attrs,
+                );
+            }
+            ast::ItemKind::Mod(unsafety, ref mod_kind) => {
+                self.head(Self::to_string(|s| {
+                    s.print_visibility(&item.vis);
+                    s.print_unsafety(unsafety);
+                    s.word("mod");
+                }));
+                self.print_ident(item.ident);
+
+                match mod_kind {
+                    ModKind::Loaded(items, ..) => {
+                        self.nbsp();
+                        self.bopen();
+                        self.print_inner_attributes(&item.attrs);
+                        for item in items {
+                            self.print_item(item);
+                        }
+                        let empty = item.attrs.is_empty() && items.is_empty();
+                        self.bclose(item.span, empty);
+                    }
+                    ModKind::Unloaded => {
+                        self.word(";");
+                        self.end(); // end inner head-block
+                        self.end(); // end outer head-block
+                    }
+                }
+            }
+            ast::ItemKind::ForeignMod(ref nmod) => {
+                self.head(Self::to_string(|s| {
+                    s.print_unsafety(nmod.unsafety);
+                    s.word("extern");
+                }));
+                if let Some(abi) = nmod.abi {
+                    self.print_literal(&abi.as_lit());
+                    self.nbsp();
+                }
+                self.bopen();
+                self.print_foreign_mod(nmod, &item.attrs);
+                let empty = item.attrs.is_empty() && nmod.items.is_empty();
+                self.bclose(item.span, empty);
+            }
+            ast::ItemKind::GlobalAsm(ref asm) => {
+                self.head(visibility_qualified(&item.vis, "global_asm!"));
+                self.print_inline_asm(asm);
+                self.end();
+            }
+            ast::ItemKind::TyAlias(box ast::TyAlias {
+                defaultness,
+                ref generics,
+                ref bounds,
+                ref ty,
+            }) => {
+                let ty = ty.as_deref();
+                self.print_associated_type(
+                    item.ident,
+                    generics,
+                    bounds,
+                    ty,
+                    &item.vis,
+                    defaultness,
+                );
+            }
+            ast::ItemKind::Enum(ref enum_definition, ref params) => {
+                self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
+            }
+            ast::ItemKind::Struct(ref struct_def, ref generics) => {
+                self.head(visibility_qualified(&item.vis, "struct"));
+                self.print_struct(struct_def, generics, item.ident, item.span, true);
+            }
+            ast::ItemKind::Union(ref struct_def, ref generics) => {
+                self.head(visibility_qualified(&item.vis, "union"));
+                self.print_struct(struct_def, generics, item.ident, item.span, true);
+            }
+            ast::ItemKind::Impl(box ast::Impl {
+                unsafety,
+                polarity,
+                defaultness,
+                constness,
+                ref generics,
+                ref of_trait,
+                ref self_ty,
+                ref items,
+            }) => {
+                self.head("");
+                self.print_visibility(&item.vis);
+                self.print_defaultness(defaultness);
+                self.print_unsafety(unsafety);
+                self.word("impl");
+
+                if generics.params.is_empty() {
+                    self.nbsp();
+                } else {
+                    self.print_generic_params(&generics.params);
+                    self.space();
+                }
+
+                self.print_constness(constness);
+
+                if let ast::ImplPolarity::Negative(_) = polarity {
+                    self.word("!");
+                }
+
+                if let Some(ref t) = *of_trait {
+                    self.print_trait_ref(t);
+                    self.space();
+                    self.word_space("for");
+                }
+
+                self.print_type(self_ty);
+                self.print_where_clause(&generics.where_clause);
+
+                self.space();
+                self.bopen();
+                self.print_inner_attributes(&item.attrs);
+                for impl_item in items {
+                    self.print_assoc_item(impl_item);
+                }
+                let empty = item.attrs.is_empty() && items.is_empty();
+                self.bclose(item.span, empty);
+            }
+            ast::ItemKind::Trait(box ast::Trait {
+                is_auto,
+                unsafety,
+                ref generics,
+                ref bounds,
+                ref items,
+                ..
+            }) => {
+                self.head("");
+                self.print_visibility(&item.vis);
+                self.print_unsafety(unsafety);
+                self.print_is_auto(is_auto);
+                self.word_nbsp("trait");
+                self.print_ident(item.ident);
+                self.print_generic_params(&generics.params);
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                for b in bounds.iter() {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                        self.space();
+                        self.word_space("for ?");
+                        self.print_trait_ref(&ptr.trait_ref);
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.print_type_bounds(":", &real_bounds);
+                self.print_where_clause(&generics.where_clause);
+                self.word(" ");
+                self.bopen();
+                self.print_inner_attributes(&item.attrs);
+                for trait_item in items {
+                    self.print_assoc_item(trait_item);
+                }
+                let empty = item.attrs.is_empty() && items.is_empty();
+                self.bclose(item.span, empty);
+            }
+            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+                self.head(visibility_qualified(&item.vis, "trait"));
+                self.print_ident(item.ident);
+                self.print_generic_params(&generics.params);
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                // FIXME(durka) this seems to be some quite outdated syntax
+                for b in bounds.iter() {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                        self.space();
+                        self.word_space("for ?");
+                        self.print_trait_ref(&ptr.trait_ref);
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.nbsp();
+                self.print_type_bounds("=", &real_bounds);
+                self.print_where_clause(&generics.where_clause);
+                self.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::MacCall(ref mac) => {
+                self.print_mac(mac);
+                if mac.args.need_semicolon() {
+                    self.word(";");
+                }
+            }
+            ast::ItemKind::MacroDef(ref macro_def) => {
+                self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
+                    state.print_visibility(&item.vis)
+                });
+            }
+        }
+        self.ann.post(self, AnnNode::Item(item))
+    }
+
+    fn print_enum_def(
+        &mut self,
+        enum_definition: &ast::EnumDef,
+        generics: &ast::Generics,
+        ident: Ident,
+        span: rustc_span::Span,
+        visibility: &ast::Visibility,
+    ) {
+        self.head(visibility_qualified(visibility, "enum"));
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        self.print_where_clause(&generics.where_clause);
+        self.space();
+        self.print_variants(&enum_definition.variants, span)
+    }
+
+    fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
+        self.bopen();
+        for v in variants {
+            self.space_if_not_bol();
+            self.maybe_print_comment(v.span.lo());
+            self.print_outer_attributes(&v.attrs);
+            self.ibox(INDENT_UNIT);
+            self.print_variant(v);
+            self.word(",");
+            self.end();
+            self.maybe_print_trailing_comment(v.span, None);
+        }
+        let empty = variants.is_empty();
+        self.bclose(span, empty)
+    }
+
+    crate fn print_visibility(&mut self, vis: &ast::Visibility) {
+        match vis.kind {
+            ast::VisibilityKind::Public => self.word_nbsp("pub"),
+            ast::VisibilityKind::Crate(sugar) => match sugar {
+                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
+                ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
+            },
+            ast::VisibilityKind::Restricted { ref path, .. } => {
+                let path = Self::to_string(|s| s.print_path(path, false, 0));
+                if path == "self" || path == "super" {
+                    self.word_nbsp(format!("pub({})", path))
+                } else {
+                    self.word_nbsp(format!("pub(in {})", path))
+                }
+            }
+            ast::VisibilityKind::Inherited => {}
+        }
+    }
+
+    fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
+        if let ast::Defaultness::Default(_) = defaultness {
+            self.word_nbsp("default");
+        }
+    }
+
+    fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
+        self.nbsp();
+        self.bopen();
+
+        let empty = fields.is_empty();
+        if !empty {
+            self.hardbreak_if_not_bol();
+
+            for field in fields {
+                self.hardbreak_if_not_bol();
+                self.maybe_print_comment(field.span.lo());
+                self.print_outer_attributes(&field.attrs);
+                self.print_visibility(&field.vis);
+                self.print_ident(field.ident.unwrap());
+                self.word_nbsp(":");
+                self.print_type(&field.ty);
+                self.word(",");
+            }
+        }
+
+        self.bclose(span, empty);
+    }
+
+    fn print_struct(
+        &mut self,
+        struct_def: &ast::VariantData,
+        generics: &ast::Generics,
+        ident: Ident,
+        span: rustc_span::Span,
+        print_finalizer: bool,
+    ) {
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        match struct_def {
+            ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+                if let ast::VariantData::Tuple(..) = struct_def {
+                    self.popen();
+                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
+                        s.maybe_print_comment(field.span.lo());
+                        s.print_outer_attributes(&field.attrs);
+                        s.print_visibility(&field.vis);
+                        s.print_type(&field.ty)
+                    });
+                    self.pclose();
+                }
+                self.print_where_clause(&generics.where_clause);
+                if print_finalizer {
+                    self.word(";");
+                }
+                self.end();
+                self.end(); // Close the outer-box.
+            }
+            ast::VariantData::Struct(ref fields, ..) => {
+                self.print_where_clause(&generics.where_clause);
+                self.print_record_struct_body(fields, span);
+            }
+        }
+    }
+
+    crate fn print_variant(&mut self, v: &ast::Variant) {
+        self.head("");
+        self.print_visibility(&v.vis);
+        let generics = ast::Generics::default();
+        self.print_struct(&v.data, &generics, v.ident, v.span, false);
+        if let Some(ref d) = v.disr_expr {
+            self.space();
+            self.word_space("=");
+            self.print_expr(&d.value)
+        }
+    }
+
+    fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+        self.ann.pre(self, AnnNode::SubItem(id));
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(span.lo());
+        self.print_outer_attributes(attrs);
+        match kind {
+            ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            }
+            ast::AssocItemKind::Const(def, ty, body) => {
+                self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
+            }
+            ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
+                self.print_associated_type(
+                    ident,
+                    generics,
+                    bounds,
+                    ty.as_deref(),
+                    vis,
+                    *defaultness,
+                );
+            }
+            ast::AssocItemKind::MacCall(m) => {
+                self.print_mac(m);
+                if m.args.need_semicolon() {
+                    self.word(";");
+                }
+            }
+        }
+        self.ann.post(self, AnnNode::SubItem(id))
+    }
+
+    fn print_fn_full(
+        &mut self,
+        sig: &ast::FnSig,
+        name: Ident,
+        generics: &ast::Generics,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+        body: Option<&ast::Block>,
+        attrs: &[ast::Attribute],
+    ) {
+        if body.is_some() {
+            self.head("");
+        }
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        self.print_fn(&sig.decl, sig.header, Some(name), generics);
+        if let Some(body) = body {
+            self.nbsp();
+            self.print_block_with_attrs(body, attrs);
+        } else {
+            self.word(";");
+        }
+    }
+
+    crate fn print_fn(
+        &mut self,
+        decl: &ast::FnDecl,
+        header: ast::FnHeader,
+        name: Option<Ident>,
+        generics: &ast::Generics,
+    ) {
+        self.print_fn_header_info(header);
+        if let Some(name) = name {
+            self.nbsp();
+            self.print_ident(name);
+        }
+        self.print_generic_params(&generics.params);
+        self.print_fn_params_and_ret(decl, false);
+        self.print_where_clause(&generics.where_clause)
+    }
+
+    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
+        self.word(open);
+        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
+        self.word(close);
+        self.print_fn_ret_ty(&decl.output)
+    }
+
+    fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
+        if where_clause.predicates.is_empty() && !where_clause.has_where_token {
+            return;
+        }
+
+        self.space();
+        self.word_space("where");
+
+        for (i, predicate) in where_clause.predicates.iter().enumerate() {
+            if i != 0 {
+                self.word_space(",");
+            }
+
+            self.print_where_predicate(predicate);
+        }
+    }
+
+    pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
+        match predicate {
+            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                bound_generic_params,
+                bounded_ty,
+                bounds,
+                ..
+            }) => {
+                self.print_formal_generic_params(bound_generic_params);
+                self.print_type(bounded_ty);
+                self.print_type_bounds(":", bounds);
+            }
+            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+                lifetime,
+                bounds,
+                ..
+            }) => {
+                self.print_lifetime_bounds(*lifetime, bounds);
+            }
+            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
+                self.print_type(lhs_ty);
+                self.space();
+                self.word_space("=");
+                self.print_type(rhs_ty);
+            }
+        }
+    }
+
+    fn print_use_tree(&mut self, tree: &ast::UseTree) {
+        match tree.kind {
+            ast::UseTreeKind::Simple(rename, ..) => {
+                self.print_path(&tree.prefix, false, 0);
+                if let Some(rename) = rename {
+                    self.space();
+                    self.word_space("as");
+                    self.print_ident(rename);
+                }
+            }
+            ast::UseTreeKind::Glob => {
+                if !tree.prefix.segments.is_empty() {
+                    self.print_path(&tree.prefix, false, 0);
+                    self.word("::");
+                }
+                self.word("*");
+            }
+            ast::UseTreeKind::Nested(ref items) => {
+                if tree.prefix.segments.is_empty() {
+                    self.word("{");
+                } else {
+                    self.print_path(&tree.prefix, false, 0);
+                    self.word("::{");
+                }
+                self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
+                    this.print_use_tree(tree)
+                });
+                self.word("}");
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 9aa58f05a8e..01cc72121c7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -779,7 +779,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                                     [
                                         hir::TypeBinding {
                                             ident: Ident { name: sym::Output, .. },
-                                            kind: hir::TypeBindingKind::Equality { ty },
+                                            kind:
+                                                hir::TypeBindingKind::Equality {
+                                                    term: hir::Term::Ty(ty),
+                                                },
                                             ..
                                         },
                                     ],
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 93384bc5511..c242c75ed18 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -6,7 +6,7 @@ use std::fmt::Write;
 
 use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir::InlineAsmOperand;
-use rustc_span::Symbol;
+use rustc_span::sym;
 use rustc_target::asm::*;
 
 pub(crate) fn codegen_inline_asm<'tcx>(
@@ -182,11 +182,7 @@ struct InlineAssemblyGenerator<'a, 'tcx> {
 impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
     fn allocate_registers(&mut self) {
         let sess = self.tcx.sess;
-        let map = allocatable_registers(
-            self.arch,
-            |feature| sess.target_features.contains(&Symbol::intern(feature)),
-            &sess.target,
-        );
+        let map = allocatable_registers(self.arch, &sess.target_features, &sess.target);
         let mut allocated = FxHashMap::<_, (bool, bool)>::default();
         let mut regs = vec![None; self.operands.len()];
 
@@ -319,9 +315,9 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
         // Allocate stack slots for saving clobbered registers
         let abi_clobber = InlineAsmClobberAbi::parse(
             self.arch,
-            |feature| self.tcx.sess.target_features.contains(&Symbol::intern(feature)),
+            &self.tcx.sess.target_features,
             &self.tcx.sess.target,
-            Symbol::intern("C"),
+            sym::C,
         )
         .unwrap()
         .clobbered_regs();
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index f4703b22ecb..55c9b4d9ba1 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -90,7 +90,7 @@ macro call_intrinsic_match {
         match $intrinsic {
             $(
                 sym::$name => {
-                    assert!($substs.is_noop());
+                    assert!($substs.is_empty());
                     if let [$(ref $arg),*] = *$args {
                         let ($($arg,)*) = (
                             $(codegen_operand($fx, $arg),)*
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index d620b24e067..b4213da6e05 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -5,7 +5,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
 
 use rustc_middle::{bug, ty::Instance};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 use rustc_target::asm::*;
 
 use std::borrow::Cow;
@@ -172,7 +172,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                             let is_target_supported = reg.reg_class().supported_types(asm_arch).iter()
                                 .any(|&(_, feature)| {
                                     if let Some(feature) = feature {
-                                        self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+                                        self.tcx.sess.target_features.contains(&feature)
                                     } else {
                                         true // Register class is unconditionally supported
                                     }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 8335f841bec..8b696dc6fba 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::{bug, span_bug, ty::Instance};
-use rustc_span::{Pos, Span, Symbol};
+use rustc_span::{Pos, Span};
 use rustc_target::abi::*;
 use rustc_target::asm::*;
 
@@ -45,9 +45,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                         for &(_, feature) in reg_class.supported_types(asm_arch) {
                             if let Some(feature) = feature {
                                 let codegen_fn_attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-                                let feature_name = Symbol::intern(feature);
-                                if self.tcx.sess.target_features.contains(&feature_name)
-                                    || codegen_fn_attrs.target_features.contains(&feature_name)
+                                if self.tcx.sess.target_features.contains(&feature)
+                                    || codegen_fn_attrs.target_features.contains(&feature)
                                 {
                                     return true;
                                 }
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 2fb5a0f9faf..5703a72c686 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -1,6 +1,7 @@
 //! A helper class for dealing with static archives
 
-use std::ffi::{CStr, CString};
+use std::env;
+use std::ffi::{CStr, CString, OsString};
 use std::io;
 use std::mem;
 use std::path::{Path, PathBuf};
@@ -158,54 +159,127 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
             output_path.with_extension("lib")
         };
 
-        // we've checked for \0 characters in the library name already
-        let dll_name_z = CString::new(lib_name).unwrap();
-        // All import names are Rust identifiers and therefore cannot contain \0 characters.
-        // FIXME: when support for #[link_name] implemented, ensure that import.name values don't
-        // have any \0 characters
-        let import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> = dll_imports
+        let mingw_gnu_toolchain = self.config.sess.target.llvm_target.ends_with("pc-windows-gnu");
+
+        let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
             .iter()
             .map(|import: &DllImport| {
                 if self.config.sess.target.arch == "x86" {
-                    (LlvmArchiveBuilder::i686_decorated_name(import), import.ordinal)
+                    (
+                        LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
+                        import.ordinal,
+                    )
                 } else {
-                    (CString::new(import.name.to_string()).unwrap(), import.ordinal)
+                    (import.name.to_string(), import.ordinal)
                 }
             })
             .collect();
 
-        let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+        if mingw_gnu_toolchain {
+            // The binutils linker used on -windows-gnu targets cannot read the import
+            // libraries generated by LLVM: in our attempts, the linker produced an .EXE
+            // that loaded but crashed with an AV upon calling one of the imported
+            // functions.  Therefore, use binutils to create the import library instead,
+            // by writing a .DEF file to the temp dir and calling binutils's dlltool.
+            let def_file_path =
+                tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def");
+
+            let def_file_content = format!(
+                "EXPORTS\n{}",
+                import_name_and_ordinal_vector
+                    .into_iter()
+                    .map(|(name, ordinal)| {
+                        match ordinal {
+                            Some(n) => format!("{} @{} NONAME", name, n),
+                            None => name,
+                        }
+                    })
+                    .collect::<Vec<String>>()
+                    .join("\n")
+            );
 
-        tracing::trace!("invoking LLVMRustWriteImportLibrary");
-        tracing::trace!("  dll_name {:#?}", dll_name_z);
-        tracing::trace!("  output_path {}", output_path.display());
-        tracing::trace!(
-            "  import names: {}",
-            dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
-        );
+            match std::fs::write(&def_file_path, def_file_content) {
+                Ok(_) => {}
+                Err(e) => {
+                    self.config.sess.fatal(&format!("Error writing .DEF file: {}", e));
+                }
+            };
 
-        let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_and_ordinal_vector
-            .iter()
-            .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
-            .collect();
-        let result = unsafe {
-            crate::llvm::LLVMRustWriteImportLibrary(
-                dll_name_z.as_ptr(),
-                output_path_z.as_ptr(),
-                ffi_exports.as_ptr(),
-                ffi_exports.len(),
-                llvm_machine_type(&self.config.sess.target.arch) as u16,
-                !self.config.sess.target.is_like_msvc,
-            )
-        };
+            let dlltool = find_binutils_dlltool(self.config.sess);
+            let result = std::process::Command::new(dlltool)
+                .args([
+                    "-d",
+                    def_file_path.to_str().unwrap(),
+                    "-D",
+                    lib_name,
+                    "-l",
+                    output_path.to_str().unwrap(),
+                ])
+                .output();
+
+            match result {
+                Err(e) => {
+                    self.config.sess.fatal(&format!("Error calling dlltool: {}", e.to_string()));
+                }
+                Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
+                    "Dlltool could not create import library: {}\n{}",
+                    String::from_utf8_lossy(&output.stdout),
+                    String::from_utf8_lossy(&output.stderr)
+                )),
+                _ => {}
+            }
+        } else {
+            // we've checked for \0 characters in the library name already
+            let dll_name_z = CString::new(lib_name).unwrap();
+
+            let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+
+            tracing::trace!("invoking LLVMRustWriteImportLibrary");
+            tracing::trace!("  dll_name {:#?}", dll_name_z);
+            tracing::trace!("  output_path {}", output_path.display());
+            tracing::trace!(
+                "  import names: {}",
+                dll_imports
+                    .iter()
+                    .map(|import| import.name.to_string())
+                    .collect::<Vec<_>>()
+                    .join(", "),
+            );
 
-        if result == crate::llvm::LLVMRustResult::Failure {
-            self.config.sess.fatal(&format!(
-                "Error creating import library for {}: {}",
-                lib_name,
-                llvm::last_error().unwrap_or("unknown LLVM error".to_string())
-            ));
-        }
+            // All import names are Rust identifiers and therefore cannot contain \0 characters.
+            // FIXME: when support for #[link_name] is implemented, ensure that the import names
+            // still don't contain any \0 characters.  Also need to check that the names don't
+            // contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
+            // in definition files.
+            let cstring_import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> =
+                import_name_and_ordinal_vector
+                    .into_iter()
+                    .map(|(name, ordinal)| (CString::new(name).unwrap(), ordinal))
+                    .collect();
+
+            let ffi_exports: Vec<LLVMRustCOFFShortExport> = cstring_import_name_and_ordinal_vector
+                .iter()
+                .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
+                .collect();
+            let result = unsafe {
+                crate::llvm::LLVMRustWriteImportLibrary(
+                    dll_name_z.as_ptr(),
+                    output_path_z.as_ptr(),
+                    ffi_exports.as_ptr(),
+                    ffi_exports.len(),
+                    llvm_machine_type(&self.config.sess.target.arch) as u16,
+                    !self.config.sess.target.is_like_msvc,
+                )
+            };
+
+            if result == crate::llvm::LLVMRustResult::Failure {
+                self.config.sess.fatal(&format!(
+                    "Error creating import library for {}: {}",
+                    lib_name,
+                    llvm::last_error().unwrap_or("unknown LLVM error".to_string())
+                ));
+            }
+        };
 
         self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
             self.config.sess.fatal(&format!(
@@ -332,22 +406,61 @@ impl<'a> LlvmArchiveBuilder<'a> {
         }
     }
 
-    fn i686_decorated_name(import: &DllImport) -> CString {
+    fn i686_decorated_name(import: &DllImport, mingw: bool) -> String {
         let name = import.name;
-        // We verified during construction that `name` does not contain any NULL characters, so the
-        // conversion to CString is guaranteed to succeed.
-        CString::new(match import.calling_convention {
-            DllCallingConvention::C => format!("_{}", name),
-            DllCallingConvention::Stdcall(arg_list_size) => format!("_{}@{}", name, arg_list_size),
+        let prefix = if mingw { "" } else { "_" };
+
+        match import.calling_convention {
+            DllCallingConvention::C => format!("{}{}", prefix, name),
+            DllCallingConvention::Stdcall(arg_list_size) => {
+                format!("{}{}@{}", prefix, name, arg_list_size)
+            }
             DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
             DllCallingConvention::Vectorcall(arg_list_size) => {
                 format!("{}@@{}", name, arg_list_size)
             }
-        })
-        .unwrap()
+        }
     }
 }
 
 fn string_to_io_error(s: String) -> io::Error {
     io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s))
 }
+
+fn find_binutils_dlltool(sess: &Session) -> OsString {
+    assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
+    if let Some(dlltool_path) = &sess.opts.debugging_opts.dlltool {
+        return dlltool_path.clone().into_os_string();
+    }
+
+    let mut tool_name: OsString = if sess.host.arch != sess.target.arch {
+        // We are cross-compiling, so we need the tool with the prefix matching our target
+        if sess.target.arch == "x86" {
+            "i686-w64-mingw32-dlltool"
+        } else {
+            "x86_64-w64-mingw32-dlltool"
+        }
+    } else {
+        // We are not cross-compiling, so we just want `dlltool`
+        "dlltool"
+    }
+    .into();
+
+    if sess.host.options.is_like_windows {
+        // If we're compiling on Windows, add the .exe suffix
+        tool_name.push(".exe");
+    }
+
+    // NOTE: it's not clear how useful it is to explicitly search PATH.
+    for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
+        let full_path = dir.join(&tool_name);
+        if full_path.is_file() {
+            return full_path.into_os_string();
+        }
+    }
+
+    // The user didn't specify the location of the dlltool binary, and we weren't able
+    // to find the appropriate one on the PATH.  Just return the name of the tool
+    // and let the invocation fail with a hopefully useful error message.
+    tool_name
+}
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index ddba43cd1f1..6afa649b6de 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -349,13 +349,6 @@ fn fat_lto(
             );
             save_temp_bitcode(cgcx, &module, "lto.after-restriction");
         }
-
-        if cgcx.no_landing_pads {
-            unsafe {
-                llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
-            }
-            save_temp_bitcode(cgcx, &module, "lto.after-nounwind");
-        }
     }
 
     Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
@@ -770,16 +763,6 @@ pub unsafe fn optimize_thin_module(
             return Err(write::llvm_err(&diag_handler, msg));
         }
 
-        // Like with "fat" LTO, get some better optimizations if landing pads
-        // are disabled by removing all landing pads.
-        if cgcx.no_landing_pads {
-            let _timer = cgcx
-                .prof
-                .generic_activity_with_arg("LLVM_thin_lto_remove_landing_pads", thin_module.name());
-            llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
-            save_temp_bitcode(cgcx, &module, "thin-lto-after-nounwind");
-        }
-
         // Up next comes the per-module local analyses that we do for Thin LTO.
         // Each of these functions is basically copied from the LLVM
         // implementation and then tailored to suit this implementation. Ideally
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 5217fa2758f..8a9450c20dd 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -731,27 +731,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
-        if !self.fptoint_sat_broken_in_llvm() {
-            let src_ty = self.cx.val_ty(val);
-            let float_width = self.cx.float_width(src_ty);
-            let int_width = self.cx.int_width(dest_ty);
-            let name = format!("llvm.fptoui.sat.i{}.f{}", int_width, float_width);
-            return Some(self.call_intrinsic(&name, &[val]));
-        }
-
-        None
+        self.fptoint_sat(false, val, dest_ty)
     }
 
     fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
-        if !self.fptoint_sat_broken_in_llvm() {
-            let src_ty = self.cx.val_ty(val);
-            let float_width = self.cx.float_width(src_ty);
-            let int_width = self.cx.int_width(dest_ty);
-            let name = format!("llvm.fptosi.sat.i{}.f{}", int_width, float_width);
-            return Some(self.call_intrinsic(&name, &[val]));
-        }
-
-        None
+        self.fptoint_sat(true, val, dest_ty)
     }
 
     fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@@ -1455,4 +1439,43 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             _ => false,
         }
     }
+
+    fn fptoint_sat(
+        &mut self,
+        signed: bool,
+        val: &'ll Value,
+        dest_ty: &'ll Type,
+    ) -> Option<&'ll Value> {
+        if !self.fptoint_sat_broken_in_llvm() {
+            let src_ty = self.cx.val_ty(val);
+            let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector
+            {
+                assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
+                (
+                    self.cx.element_type(src_ty),
+                    self.cx.element_type(dest_ty),
+                    Some(self.cx.vector_length(src_ty)),
+                )
+            } else {
+                (src_ty, dest_ty, None)
+            };
+            let float_width = self.cx.float_width(float_ty);
+            let int_width = self.cx.int_width(int_ty);
+
+            let instr = if signed { "fptosi" } else { "fptoui" };
+            let name = if let Some(vector_length) = vector_length {
+                format!(
+                    "llvm.{}.sat.v{}i{}.v{}f{}",
+                    instr, vector_length, int_width, vector_length, float_width
+                )
+            } else {
+                format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
+            };
+            let f =
+                self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
+            Some(self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None))
+        } else {
+            None
+        }
+    }
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 5c02e3d0fa7..3d5fd2f354e 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -27,18 +27,18 @@ use rustc_fs_util::path_to_c_string;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::bug;
 use rustc_middle::mir::{self, GeneratorLayout};
 use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{
     self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES,
 };
-use rustc_middle::{bug, span_bug};
 use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_session::config::{self, DebugInfo};
 use rustc_span::symbol::Symbol;
 use rustc_span::FileNameDisplayPreference;
-use rustc_span::{self, SourceFile, SourceFileHash, Span};
+use rustc_span::{self, SourceFile, SourceFileHash};
 use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, TagEncoding};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
@@ -381,9 +381,8 @@ fn fixed_vec_metadata<'ll, 'tcx>(
     unique_type_id: UniqueTypeId,
     array_or_slice_type: Ty<'tcx>,
     element_type: Ty<'tcx>,
-    span: Span,
 ) -> MetadataCreationResult<'ll> {
-    let element_type_metadata = type_metadata(cx, element_type, span);
+    let element_type_metadata = type_metadata(cx, element_type);
 
     return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
@@ -416,11 +415,10 @@ fn vec_slice_metadata<'ll, 'tcx>(
     slice_ptr_type: Ty<'tcx>,
     element_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
-    span: Span,
 ) -> MetadataCreationResult<'ll> {
     let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
 
-    let data_ptr_metadata = type_metadata(cx, data_ptr_type, span);
+    let data_ptr_metadata = type_metadata(cx, data_ptr_type);
 
     return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
@@ -442,7 +440,7 @@ fn vec_slice_metadata<'ll, 'tcx>(
         },
         MemberDescription {
             name: "length".to_owned(),
-            type_metadata: type_metadata(cx, cx.tcx.types.usize, span),
+            type_metadata: type_metadata(cx, cx.tcx.types.usize),
             offset: pointer_size,
             size: usize_size,
             align: usize_align,
@@ -452,8 +450,6 @@ fn vec_slice_metadata<'ll, 'tcx>(
         },
     ];
 
-    let file_metadata = unknown_file_metadata(cx);
-
     let metadata = composite_type_metadata(
         cx,
         slice_ptr_type,
@@ -461,8 +457,6 @@ fn vec_slice_metadata<'ll, 'tcx>(
         unique_type_id,
         member_descriptions,
         NO_SCOPE_METADATA,
-        file_metadata,
-        span,
     );
     MetadataCreationResult::new(metadata, false)
 }
@@ -471,7 +465,6 @@ fn subroutine_type_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     unique_type_id: UniqueTypeId,
     signature: ty::PolyFnSig<'tcx>,
-    span: Span,
 ) -> MetadataCreationResult<'ll> {
     let signature =
         cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature);
@@ -480,12 +473,12 @@ fn subroutine_type_metadata<'ll, 'tcx>(
         // return type
         match signature.output().kind() {
             ty::Tuple(tys) if tys.is_empty() => None,
-            _ => Some(type_metadata(cx, signature.output(), span)),
+            _ => Some(type_metadata(cx, signature.output())),
         },
     )
     .chain(
         // regular arguments
-        signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type, span))),
+        signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type))),
     )
     .collect();
 
@@ -541,8 +534,6 @@ fn trait_pointer_metadata<'ll, 'tcx>(
         None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
     };
 
-    let file_metadata = unknown_file_metadata(cx);
-
     let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
 
     assert_eq!(abi::FAT_PTR_ADDR, 0);
@@ -553,11 +544,7 @@ fn trait_pointer_metadata<'ll, 'tcx>(
     let member_descriptions = vec![
         MemberDescription {
             name: "pointer".to_owned(),
-            type_metadata: type_metadata(
-                cx,
-                cx.tcx.mk_mut_ptr(cx.tcx.types.u8),
-                rustc_span::DUMMY_SP,
-            ),
+            type_metadata: type_metadata(cx, cx.tcx.mk_mut_ptr(cx.tcx.types.u8)),
             offset: layout.fields.offset(0),
             size: data_ptr_field.size,
             align: data_ptr_field.align.abi,
@@ -567,7 +554,7 @@ fn trait_pointer_metadata<'ll, 'tcx>(
         },
         MemberDescription {
             name: "vtable".to_owned(),
-            type_metadata: type_metadata(cx, vtable_field.ty, rustc_span::DUMMY_SP),
+            type_metadata: type_metadata(cx, vtable_field.ty),
             offset: layout.fields.offset(1),
             size: vtable_field.size,
             align: vtable_field.align.abi,
@@ -584,16 +571,10 @@ fn trait_pointer_metadata<'ll, 'tcx>(
         unique_type_id,
         member_descriptions,
         containing_scope,
-        file_metadata,
-        rustc_span::DUMMY_SP,
     )
 }
 
-pub fn type_metadata<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    t: Ty<'tcx>,
-    usage_site_span: Span,
-) -> &'ll DIType {
+pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
     // Get the unique type ID of this type.
     let unique_type_id = {
         let mut type_map = debug_context(cx).type_map.borrow_mut();
@@ -630,14 +611,14 @@ pub fn type_metadata<'ll, 'tcx>(
     debug!("type_metadata: {:?}", t);
 
     let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() {
-        ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)),
-        ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)),
+        ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id)),
+        ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id)),
         ty::Dynamic(..) => Ok(MetadataCreationResult::new(
             trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
             false,
         )),
         _ => {
-            let pointee_metadata = type_metadata(cx, ty, usage_site_span);
+            let pointee_metadata = type_metadata(cx, ty);
 
             if let Some(metadata) =
                 debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
@@ -656,10 +637,8 @@ pub fn type_metadata<'ll, 'tcx>(
         ty::Tuple(elements) if elements.is_empty() => {
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
         }
-        ty::Array(typ, _) | ty::Slice(typ) => {
-            fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span)
-        }
-        ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span),
+        ty::Array(typ, _) | ty::Slice(typ) => fixed_vec_metadata(cx, unique_type_id, t, typ),
+        ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8),
         ty::Dynamic(..) => {
             MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false)
         }
@@ -710,8 +689,7 @@ pub fn type_metadata<'ll, 'tcx>(
             type_map.borrow_mut().register_type_with_metadata(t, temp_type);
 
             let fn_metadata =
-                subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx), usage_site_span)
-                    .metadata;
+                subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx)).metadata;
 
             type_map.borrow_mut().remove_type(t);
 
@@ -721,15 +699,8 @@ pub fn type_metadata<'ll, 'tcx>(
         ty::Closure(def_id, substs) => {
             let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
             let containing_scope = get_namespace_for_item(cx, def_id);
-            prepare_tuple_metadata(
-                cx,
-                t,
-                &upvar_tys,
-                unique_type_id,
-                usage_site_span,
-                Some(containing_scope),
-            )
-            .finalize(cx)
+            prepare_tuple_metadata(cx, t, &upvar_tys, unique_type_id, Some(containing_scope))
+                .finalize(cx)
         }
         ty::Generator(def_id, substs, _) => {
             let upvar_tys: Vec<_> = substs
@@ -737,25 +708,18 @@ pub fn type_metadata<'ll, 'tcx>(
                 .prefix_tys()
                 .map(|t| cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
                 .collect();
-            prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span, upvar_tys)
-                .finalize(cx)
+            prepare_enum_metadata(cx, t, def_id, unique_type_id, upvar_tys).finalize(cx)
         }
         ty::Adt(def, ..) => match def.adt_kind() {
-            AdtKind::Struct => {
-                prepare_struct_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
-            }
-            AdtKind::Union => {
-                prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
-            }
+            AdtKind::Struct => prepare_struct_metadata(cx, t, unique_type_id).finalize(cx),
+            AdtKind::Union => prepare_union_metadata(cx, t, unique_type_id).finalize(cx),
             AdtKind::Enum => {
-                prepare_enum_metadata(cx, t, def.did, unique_type_id, usage_site_span, vec![])
-                    .finalize(cx)
+                prepare_enum_metadata(cx, t, def.did, unique_type_id, vec![]).finalize(cx)
             }
         },
         ty::Tuple(elements) => {
             let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect();
-            prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
-                .finalize(cx)
+            prepare_tuple_metadata(cx, t, &tys, unique_type_id, NO_SCOPE_METADATA).finalize(cx)
         }
         // Type parameters from polymorphized functions.
         ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false),
@@ -770,8 +734,7 @@ pub fn type_metadata<'ll, 'tcx>(
             let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) {
                 Some(metadata) => metadata,
                 None => {
-                    span_bug!(
-                        usage_site_span,
+                    bug!(
                         "expected type metadata for unique \
                                type ID '{}' to already be in \
                                the `debuginfo::TypeMap` but it \
@@ -785,8 +748,7 @@ pub fn type_metadata<'ll, 'tcx>(
             match type_map.find_metadata_for_type(t) {
                 Some(metadata) => {
                     if metadata != metadata_for_uid {
-                        span_bug!(
-                            usage_site_span,
+                        bug!(
                             "mismatch between `Ty` and \
                                    `UniqueTypeId` maps in \
                                    `debuginfo::TypeMap`. \
@@ -1283,7 +1245,6 @@ impl<'ll, 'tcx> MemberDescriptionFactory<'ll, 'tcx> {
 struct StructMemberDescriptionFactory<'tcx> {
     ty: Ty<'tcx>,
     variant: &'tcx ty::VariantDef,
-    span: Span,
 }
 
 impl<'tcx> StructMemberDescriptionFactory<'tcx> {
@@ -1305,7 +1266,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
                 let field = layout.field(cx, i);
                 MemberDescription {
                     name,
-                    type_metadata: type_metadata(cx, field.ty, self.span),
+                    type_metadata: type_metadata(cx, field.ty),
                     offset: layout.fields.offset(i),
                     size: field.size,
                     align: field.align.abi,
@@ -1322,7 +1283,6 @@ fn prepare_struct_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     struct_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
-    span: Span,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
 
@@ -1348,7 +1308,7 @@ fn prepare_struct_metadata<'ll, 'tcx>(
         unique_type_id,
         struct_metadata_stub,
         struct_metadata_stub,
-        StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant, span }),
+        StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant }),
     )
 }
 
@@ -1385,7 +1345,6 @@ fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'_>, def_id: DefId) ->
 struct TupleMemberDescriptionFactory<'tcx> {
     ty: Ty<'tcx>,
     component_types: Vec<Ty<'tcx>>,
-    span: Span,
 }
 
 impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
@@ -1412,7 +1371,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
                 };
                 MemberDescription {
                     name,
-                    type_metadata: type_metadata(cx, component_type, self.span),
+                    type_metadata: type_metadata(cx, component_type),
                     offset: layout.fields.offset(i),
                     size,
                     align,
@@ -1430,7 +1389,6 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
     tuple_type: Ty<'tcx>,
     component_types: &[Ty<'tcx>],
     unique_type_id: UniqueTypeId,
-    span: Span,
     containing_scope: Option<&'ll DIScope>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
@@ -1453,7 +1411,6 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
         TupleMDF(TupleMemberDescriptionFactory {
             ty: tuple_type,
             component_types: component_types.to_vec(),
-            span,
         }),
     )
 }
@@ -1465,7 +1422,6 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
 struct UnionMemberDescriptionFactory<'tcx> {
     layout: TyAndLayout<'tcx>,
     variant: &'tcx ty::VariantDef,
-    span: Span,
 }
 
 impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
@@ -1481,7 +1437,7 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
                 let field = self.layout.field(cx, i);
                 MemberDescription {
                     name: f.name.to_string(),
-                    type_metadata: type_metadata(cx, field.ty, self.span),
+                    type_metadata: type_metadata(cx, field.ty),
                     offset: Size::ZERO,
                     size: field.size,
                     align: field.align.abi,
@@ -1498,7 +1454,6 @@ fn prepare_union_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     union_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
-    span: Span,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
 
@@ -1518,7 +1473,7 @@ fn prepare_union_metadata<'ll, 'tcx>(
         unique_type_id,
         union_metadata_stub,
         union_metadata_stub,
-        UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant, span }),
+        UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant }),
     )
 }
 
@@ -1573,7 +1528,6 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
     layout: TyAndLayout<'tcx>,
     tag_type_metadata: Option<&'ll DIType>,
     common_members: Vec<Option<&'ll DIType>>,
-    span: Span,
 }
 
 impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
@@ -1605,7 +1559,7 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
         // msvc, then we need to use a different, fallback encoding of the debuginfo.
         let fallback = cpp_like_debuginfo(cx.tcx);
         // This will always find the metadata in the type map.
-        let self_metadata = type_metadata(cx, self.enum_type, self.span);
+        let self_metadata = type_metadata(cx, self.enum_type);
 
         match self.layout.variants {
             Variants::Single { index } => {
@@ -1617,7 +1571,7 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
 
                 let variant_info = variant_info_for(index);
                 let (variant_type_metadata, member_description_factory) =
-                    describe_enum_variant(cx, self.layout, variant_info, self_metadata, self.span);
+                    describe_enum_variant(cx, self.layout, variant_info, self_metadata);
 
                 let member_descriptions = member_description_factory.create_member_descriptions(cx);
 
@@ -1682,13 +1636,8 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
                     .map(|(i, _)| {
                         let variant = self.layout.for_variant(cx, i);
                         let variant_info = variant_info_for(i);
-                        let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
-                            cx,
-                            variant,
-                            variant_info,
-                            self_metadata,
-                            self.span,
-                        );
+                        let (variant_type_metadata, member_desc_factory) =
+                            describe_enum_variant(cx, variant, variant_info, self_metadata);
 
                         let member_descriptions =
                             member_desc_factory.create_member_descriptions(cx);
@@ -1807,7 +1756,7 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
                             tag.value.size(cx).bits(),
                             tag.value.align(cx).abi.bits() as u32,
                             create_DIArray(DIB(cx), &tags),
-                            type_metadata(cx, discr_enum_ty, self.span),
+                            type_metadata(cx, discr_enum_ty),
                             true,
                         )
                     };
@@ -1818,7 +1767,6 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
                         dataful_variant_layout,
                         variant_info,
                         self_metadata,
-                        self.span,
                     );
 
                     let member_descriptions = member_desc_factory.create_member_descriptions(cx);
@@ -1864,13 +1812,7 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
                             let variant = self.layout.for_variant(cx, i);
                             let variant_info = variant_info_for(i);
                             let (variant_type_metadata, member_desc_factory) =
-                                describe_enum_variant(
-                                    cx,
-                                    variant,
-                                    variant_info,
-                                    self_metadata,
-                                    self.span,
-                                );
+                                describe_enum_variant(cx, variant, variant_info, self_metadata);
 
                             let member_descriptions =
                                 member_desc_factory.create_member_descriptions(cx);
@@ -1908,7 +1850,6 @@ struct VariantMemberDescriptionFactory<'tcx> {
     /// Cloned from the `layout::Struct` describing the variant.
     offsets: Vec<Size>,
     args: Vec<(String, Ty<'tcx>)>,
-    span: Span,
 }
 
 impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
@@ -1923,7 +1864,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
                 let (size, align) = cx.size_and_align_of(ty);
                 MemberDescription {
                     name: name.to_string(),
-                    type_metadata: type_metadata(cx, ty, self.span),
+                    type_metadata: type_metadata(cx, ty),
                     offset: self.offsets[i],
                     size,
                     align,
@@ -2011,7 +1952,6 @@ fn describe_enum_variant<'ll, 'tcx>(
     layout: layout::TyAndLayout<'tcx>,
     variant: VariantInfo<'_, 'tcx>,
     containing_scope: &'ll DIScope,
-    span: Span,
 ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
     let metadata_stub = variant.map_struct_name(|variant_name| {
         let unique_type_id = debug_context(cx)
@@ -2033,8 +1973,7 @@ fn describe_enum_variant<'ll, 'tcx>(
         .map(|i| (variant.field_name(i), layout.field(cx, i).ty))
         .collect();
 
-    let member_description_factory =
-        VariantMDF(VariantMemberDescriptionFactory { offsets, args, span });
+    let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { offsets, args });
 
     (metadata_stub, member_description_factory)
 }
@@ -2044,7 +1983,6 @@ fn prepare_enum_metadata<'ll, 'tcx>(
     enum_type: Ty<'tcx>,
     enum_def_id: DefId,
     unique_type_id: UniqueTypeId,
-    span: Span,
     outer_field_tys: Vec<Ty<'tcx>>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tcx = cx.tcx;
@@ -2109,8 +2047,7 @@ fn prepare_enum_metadata<'ll, 'tcx>(
             Some(discriminant_type_metadata) => discriminant_type_metadata,
             None => {
                 let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx));
-                let discriminant_base_type_metadata =
-                    type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP);
+                let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(tcx));
 
                 let item_name;
                 let discriminant_name = match enum_type.kind() {
@@ -2202,7 +2139,6 @@ fn prepare_enum_metadata<'ll, 'tcx>(
                 layout,
                 tag_type_metadata: discriminant_type_metadata,
                 common_members: vec![],
-                span,
             }),
         );
     }
@@ -2272,11 +2208,8 @@ fn prepare_enum_metadata<'ll, 'tcx>(
     let outer_fields = match layout.variants {
         Variants::Single { .. } => vec![],
         Variants::Multiple { .. } => {
-            let tuple_mdf = TupleMemberDescriptionFactory {
-                ty: enum_type,
-                component_types: outer_field_tys,
-                span,
-            };
+            let tuple_mdf =
+                TupleMemberDescriptionFactory { ty: enum_type, component_types: outer_field_tys };
             tuple_mdf
                 .create_member_descriptions(cx)
                 .into_iter()
@@ -2352,7 +2285,6 @@ fn prepare_enum_metadata<'ll, 'tcx>(
             layout,
             tag_type_metadata: None,
             common_members: outer_fields,
-            span,
         }),
     )
 }
@@ -2368,11 +2300,6 @@ fn composite_type_metadata<'ll, 'tcx>(
     composite_type_unique_id: UniqueTypeId,
     member_descriptions: Vec<MemberDescription<'ll>>,
     containing_scope: Option<&'ll DIScope>,
-
-    // Ignore source location information as long as it
-    // can't be reconstructed for non-local crates.
-    _file_metadata: &'ll DIFile,
-    _definition_span: Span,
 ) -> &'ll DICompositeType {
     // Create the (empty) struct metadata node ...
     let composite_type_metadata = create_struct_stub(
@@ -2450,8 +2377,7 @@ fn compute_type_parameters<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -
                     if let GenericArgKind::Type(ty) = kind.unpack() {
                         let actual_type =
                             cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
-                        let actual_type_metadata =
-                            type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+                        let actual_type_metadata = type_metadata(cx, actual_type);
                         let name = name.as_str();
                         Some(unsafe {
                             Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
@@ -2593,7 +2519,7 @@ pub fn create_global_var_metadata<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, g
 
     let is_local_to_unit = is_node_local_to_unit(cx, def_id);
     let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
-    let type_metadata = type_metadata(cx, variable_type, span);
+    let type_metadata = type_metadata(cx, variable_type);
     let var_name = tcx.item_name(def_id);
     let var_name = var_name.as_str();
     let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
@@ -2648,7 +2574,7 @@ fn vtable_type_metadata<'ll, 'tcx>(
     //        things simple instead of adding some ad-hoc disambiguation scheme.
     let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64);
 
-    type_metadata(cx, vtable_type, rustc_span::DUMMY_SP)
+    type_metadata(cx, vtable_type)
 }
 
 /// Creates debug information for the given vtable, which is for the
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index d1cea147a7a..61e49fab6ff 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -390,7 +390,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             signature.push(if fn_abi.ret.is_ignore() {
                 None
             } else {
-                Some(type_metadata(cx, fn_abi.ret.layout.ty, rustc_span::DUMMY_SP))
+                Some(type_metadata(cx, fn_abi.ret.layout.ty))
             });
 
             // Arguments types
@@ -415,15 +415,11 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                         }
                         _ => t,
                     };
-                    Some(type_metadata(cx, t, rustc_span::DUMMY_SP))
+                    Some(type_metadata(cx, t))
                 }));
             } else {
-                signature.extend(
-                    fn_abi
-                        .args
-                        .iter()
-                        .map(|arg| Some(type_metadata(cx, arg.layout.ty, rustc_span::DUMMY_SP))),
-                );
+                signature
+                    .extend(fn_abi.args.iter().map(|arg| Some(type_metadata(cx, arg.layout.ty))));
             }
 
             create_DIArray(DIB(cx), &signature[..])
@@ -453,8 +449,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                         if let GenericArgKind::Type(ty) = kind.unpack() {
                             let actual_type =
                                 cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
-                            let actual_type_metadata =
-                                type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+                            let actual_type_metadata = type_metadata(cx, actual_type);
                             let name = name.as_str();
                             Some(unsafe {
                                 Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
@@ -509,7 +504,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                             if cx.sess().opts.debuginfo == DebugInfo::Full
                                 && !impl_self_ty.needs_subst()
                             {
-                                Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
+                                Some(type_metadata(cx, impl_self_ty))
                             } else {
                                 Some(namespace::item_namespace(cx, def.did))
                             }
@@ -584,7 +579,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let loc = self.lookup_debug_loc(span.lo());
         let file_metadata = file_metadata(self, &loc.file);
 
-        let type_metadata = type_metadata(self, variable_type, span);
+        let type_metadata = type_metadata(self, variable_type);
 
         let (argument_index, dwarf_tag) = match variable_kind {
             ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index cebb6d13c4e..5adfa18035a 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1688,7 +1688,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
     bitwise_red!(simd_reduce_all: vector_reduce_and, true);
     bitwise_red!(simd_reduce_any: vector_reduce_or, true);
 
-    if name == sym::simd_cast {
+    if name == sym::simd_cast || name == sym::simd_as {
         require_simd!(ret_ty, "return");
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
@@ -1714,14 +1714,26 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
         let (in_style, in_width) = match in_elem.kind() {
             // vectors of pointer-sized integers should've been
             // disallowed before here, so this unwrap is safe.
-            ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()),
-            ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()),
+            ty::Int(i) => (
+                Style::Int(true),
+                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Uint(u) => (
+                Style::Int(false),
+                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
             ty::Float(f) => (Style::Float, f.bit_width()),
             _ => (Style::Unsupported, 0),
         };
         let (out_style, out_width) = match out_elem.kind() {
-            ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()),
-            ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()),
+            ty::Int(i) => (
+                Style::Int(true),
+                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Uint(u) => (
+                Style::Int(false),
+                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
             ty::Float(f) => (Style::Float, f.bit_width()),
             _ => (Style::Unsupported, 0),
         };
@@ -1748,10 +1760,10 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
                 });
             }
             (Style::Float, Style::Int(out_is_signed)) => {
-                return Ok(if out_is_signed {
-                    bx.fptosi(args[0].immediate(), llret_ty)
-                } else {
-                    bx.fptoui(args[0].immediate(), llret_ty)
+                return Ok(match (out_is_signed, name == sym::simd_as) {
+                    (false, false) => bx.fptoui(args[0].immediate(), llret_ty),
+                    (true, false) => bx.fptosi(args[0].immediate(), llret_ty),
+                    (_, true) => bx.cast_float_to_int(out_is_signed, args[0].immediate(), llret_ty),
                 });
             }
             (Style::Float, Style::Float) => {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index bc8d7b3e9e2..a1c7d2b4f61 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2320,7 +2320,6 @@ extern "C" {
     pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
     pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
     pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
-    pub fn LLVMRustMarkAllFunctionsNounwind(M: &Module);
 
     pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
     pub fn LLVMRustArchiveIteratorNew(AR: &Archive) -> &mut ArchiveIterator<'_>;
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index f7fe194d207..acf65259f61 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -667,7 +667,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         cmd.env_remove(k);
     }
 
-    if sess.opts.debugging_opts.print_link_args {
+    if sess.opts.prints.contains(&PrintRequest::LinkArgs) {
         println!("{:?}", &cmd);
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index bea454458c4..540979ce02d 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -32,7 +32,7 @@ use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
-use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet};
+use rustc_target::spec::{MergeFunctions, SanitizerSet};
 
 use std::any::Any;
 use std::fs;
@@ -313,7 +313,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub backend: B,
     pub prof: SelfProfilerRef,
     pub lto: Lto,
-    pub no_landing_pads: bool,
     pub save_temps: bool,
     pub fewer_names: bool,
     pub time_trace: bool,
@@ -1039,7 +1038,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         crate_types: sess.crate_types().to_vec(),
         each_linked_rlib_for_lto,
         lto: sess.lto(),
-        no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
         fewer_names: sess.fewer_names(),
         save_temps: sess.opts.cg.save_temps,
         time_trace: sess.opts.debugging_opts.llvm_time_trace,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 61322a6e556..9687fd09a53 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -203,8 +203,9 @@ fn push_debuginfo_type_name<'tcx>(
                 let projection_bounds: SmallVec<[_; 4]> = trait_data
                     .projection_bounds()
                     .map(|bound| {
-                        let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
-                        (item_def_id, ty)
+                        let ExistentialProjection { item_def_id, term, .. } = bound.skip_binder();
+                        // FIXME(associated_const_equality): allow for consts here
+                        (item_def_id, term.ty().unwrap())
                     })
                     .collect();
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 4b07ed1a1e6..c21d19a6227 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -429,87 +429,78 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let cx = self.cx;
         let tcx = self.cx.tcx();
 
-        let result = match place_ref {
-            mir::PlaceRef { local, projection: [] } => match self.locals[local] {
-                LocalRef::Place(place) => {
-                    return place;
-                }
-                LocalRef::UnsizedPlace(place) => {
-                    return bx.load_operand(place).deref(cx);
-                }
-                LocalRef::Operand(..) => {
+        let mut base = 0;
+        let mut cg_base = match self.locals[place_ref.local] {
+            LocalRef::Place(place) => place,
+            LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx),
+            LocalRef::Operand(..) => {
+                if let Some(elem) = place_ref
+                    .projection
+                    .iter()
+                    .enumerate()
+                    .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref))
+                {
+                    base = elem.0 + 1;
+                    self.codegen_consume(
+                        bx,
+                        mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref },
+                    )
+                    .deref(bx.cx())
+                } else {
                     bug!("using operand local {:?} as place", place_ref);
                 }
-            },
-            mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
-                // Load the pointer from its location.
-                self.codegen_consume(bx, mir::PlaceRef { local, projection: proj_base })
-                    .deref(bx.cx())
             }
-            mir::PlaceRef { local, projection: &[ref proj_base @ .., elem] } => {
-                // FIXME turn this recursion into iteration
-                let cg_base =
-                    self.codegen_place(bx, mir::PlaceRef { local, projection: proj_base });
-
-                match elem {
-                    mir::ProjectionElem::Deref => bug!(),
-                    mir::ProjectionElem::Field(ref field, _) => {
-                        cg_base.project_field(bx, field.index())
-                    }
-                    mir::ProjectionElem::Index(index) => {
-                        let index = &mir::Operand::Copy(mir::Place::from(index));
-                        let index = self.codegen_operand(bx, index);
-                        let llindex = index.immediate();
-                        cg_base.project_index(bx, llindex)
-                    }
-                    mir::ProjectionElem::ConstantIndex {
-                        offset,
-                        from_end: false,
-                        min_length: _,
-                    } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
-                        cg_base.project_index(bx, lloffset)
-                    }
-                    mir::ProjectionElem::ConstantIndex {
-                        offset,
-                        from_end: true,
-                        min_length: _,
-                    } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
-                        let lllen = cg_base.len(bx.cx());
-                        let llindex = bx.sub(lllen, lloffset);
-                        cg_base.project_index(bx, llindex)
-                    }
-                    mir::ProjectionElem::Subslice { from, to, from_end } => {
-                        let mut subslice =
-                            cg_base.project_index(bx, bx.cx().const_usize(from as u64));
-                        let projected_ty =
-                            PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty;
-                        subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
-
-                        if subslice.layout.is_unsized() {
-                            assert!(from_end, "slice subslices should be `from_end`");
-                            subslice.llextra = Some(bx.sub(
-                                cg_base.llextra.unwrap(),
-                                bx.cx().const_usize((from as u64) + (to as u64)),
-                            ));
-                        }
-
-                        // Cast the place pointer type to the new
-                        // array or slice type (`*[%_; new_len]`).
-                        subslice.llval = bx.pointercast(
-                            subslice.llval,
-                            bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)),
-                        );
-
-                        subslice
+        };
+        for elem in place_ref.projection[base..].iter() {
+            cg_base = match elem.clone() {
+                mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
+                mir::ProjectionElem::Field(ref field, _) => {
+                    cg_base.project_field(bx, field.index())
+                }
+                mir::ProjectionElem::Index(index) => {
+                    let index = &mir::Operand::Copy(mir::Place::from(index));
+                    let index = self.codegen_operand(bx, index);
+                    let llindex = index.immediate();
+                    cg_base.project_index(bx, llindex)
+                }
+                mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => {
+                    let lloffset = bx.cx().const_usize(offset as u64);
+                    cg_base.project_index(bx, lloffset)
+                }
+                mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => {
+                    let lloffset = bx.cx().const_usize(offset as u64);
+                    let lllen = cg_base.len(bx.cx());
+                    let llindex = bx.sub(lllen, lloffset);
+                    cg_base.project_index(bx, llindex)
+                }
+                mir::ProjectionElem::Subslice { from, to, from_end } => {
+                    let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64));
+                    let projected_ty =
+                        PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem.clone()).ty;
+                    subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
+
+                    if subslice.layout.is_unsized() {
+                        assert!(from_end, "slice subslices should be `from_end`");
+                        subslice.llextra = Some(bx.sub(
+                            cg_base.llextra.unwrap(),
+                            bx.cx().const_usize((from as u64) + (to as u64)),
+                        ));
                     }
-                    mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
+
+                    // Cast the place pointer type to the new
+                    // array or slice type (`*[%_; new_len]`).
+                    subslice.llval = bx.pointercast(
+                        subslice.llval,
+                        bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)),
+                    );
+
+                    subslice
                 }
-            }
-        };
-        debug!("codegen_place(place={:?}) => {:?}", place_ref, result);
-        result
+                mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
+            };
+        }
+        debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);
+        cg_base
     }
 
     pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 679c4576701..68decce82ab 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -3,11 +3,10 @@ use super::place::PlaceRef;
 use super::{FunctionCx, LocalRef};
 
 use crate::base;
-use crate::common::{self, IntPredicate, RealPredicate};
+use crate::common::{self, IntPredicate};
 use crate::traits::*;
 use crate::MemFlags;
 
-use rustc_apfloat::{ieee, Float, Round, Status};
 use rustc_middle::mir;
 use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
@@ -368,10 +367,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 bx.inttoptr(usize_llval, ll_t_out)
                             }
                             (CastTy::Float, CastTy::Int(IntTy::I)) => {
-                                cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out)
+                                bx.cast_float_to_int(true, llval, ll_t_out)
                             }
                             (CastTy::Float, CastTy::Int(_)) => {
-                                cast_float_to_int(&mut bx, false, llval, ll_t_in, ll_t_out)
+                                bx.cast_float_to_int(false, llval, ll_t_out)
                             }
                             _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty),
                         };
@@ -768,146 +767,3 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // (*) this is only true if the type is suitable
     }
 }
-
-fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    signed: bool,
-    x: Bx::Value,
-    float_ty: Bx::Type,
-    int_ty: Bx::Type,
-) -> Bx::Value {
-    if let Some(false) = bx.cx().sess().opts.debugging_opts.saturating_float_casts {
-        return if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
-    }
-
-    let try_sat_result = if signed { bx.fptosi_sat(x, int_ty) } else { bx.fptoui_sat(x, int_ty) };
-    if let Some(try_sat_result) = try_sat_result {
-        return try_sat_result;
-    }
-
-    let int_width = bx.cx().int_width(int_ty);
-    let float_width = bx.cx().float_width(float_ty);
-    // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
-    // destination integer type after rounding towards zero. This `undef` value can cause UB in
-    // safe code (see issue #10184), so we implement a saturating conversion on top of it:
-    // Semantically, the mathematical value of the input is rounded towards zero to the next
-    // mathematical integer, and then the result is clamped into the range of the destination
-    // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
-    // the destination integer type. NaN is mapped to 0.
-    //
-    // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
-    // a value representable in int_ty.
-    // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
-    // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
-    // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
-    // representable. Note that this only works if float_ty's exponent range is sufficiently large.
-    // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
-    // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
-    // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
-    // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
-    // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
-    let int_max = |signed: bool, int_width: u64| -> u128 {
-        let shift_amount = 128 - int_width;
-        if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
-    };
-    let int_min = |signed: bool, int_width: u64| -> i128 {
-        if signed { i128::MIN >> (128 - int_width) } else { 0 }
-    };
-
-    let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
-        let rounded_min = ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
-        assert_eq!(rounded_min.status, Status::OK);
-        let rounded_max = ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
-        assert!(rounded_max.value.is_finite());
-        (rounded_min.value.to_bits(), rounded_max.value.to_bits())
-    };
-    let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
-        let rounded_min = ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
-        assert_eq!(rounded_min.status, Status::OK);
-        let rounded_max = ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
-        assert!(rounded_max.value.is_finite());
-        (rounded_min.value.to_bits(), rounded_max.value.to_bits())
-    };
-
-    let mut float_bits_to_llval = |bits| {
-        let bits_llval = match float_width {
-            32 => bx.cx().const_u32(bits as u32),
-            64 => bx.cx().const_u64(bits as u64),
-            n => bug!("unsupported float width {}", n),
-        };
-        bx.bitcast(bits_llval, float_ty)
-    };
-    let (f_min, f_max) = match float_width {
-        32 => compute_clamp_bounds_single(signed, int_width),
-        64 => compute_clamp_bounds_double(signed, int_width),
-        n => bug!("unsupported float width {}", n),
-    };
-    let f_min = float_bits_to_llval(f_min);
-    let f_max = float_bits_to_llval(f_max);
-    // To implement saturation, we perform the following steps:
-    //
-    // 1. Cast x to an integer with fpto[su]i. This may result in undef.
-    // 2. Compare x to f_min and f_max, and use the comparison results to select:
-    //  a) int_ty::MIN if x < f_min or x is NaN
-    //  b) int_ty::MAX if x > f_max
-    //  c) the result of fpto[su]i otherwise
-    // 3. If x is NaN, return 0.0, otherwise return the result of step 2.
-    //
-    // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
-    // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
-    // undef does not introduce any non-determinism either.
-    // More importantly, the above procedure correctly implements saturating conversion.
-    // Proof (sketch):
-    // If x is NaN, 0 is returned by definition.
-    // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
-    // This yields three cases to consider:
-    // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
-    //     saturating conversion for inputs in that range.
-    // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded
-    //     (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
-    //     than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX
-    //     is correct.
-    // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
-    //     int_ty::MIN and therefore the return value of int_ty::MIN is correct.
-    // QED.
-
-    let int_max = bx.cx().const_uint_big(int_ty, int_max(signed, int_width));
-    let int_min = bx.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
-    let zero = bx.cx().const_uint(int_ty, 0);
-
-    // Step 1 ...
-    let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
-    let less_or_nan = bx.fcmp(RealPredicate::RealULT, x, f_min);
-    let greater = bx.fcmp(RealPredicate::RealOGT, x, f_max);
-
-    // Step 2: We use two comparisons and two selects, with %s1 being the
-    // result:
-    //     %less_or_nan = fcmp ult %x, %f_min
-    //     %greater = fcmp olt %x, %f_max
-    //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
-    //     %s1 = select %greater, int_ty::MAX, %s0
-    // Note that %less_or_nan uses an *unordered* comparison. This
-    // comparison is true if the operands are not comparable (i.e., if x is
-    // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
-    // x is NaN.
-    //
-    // Performance note: Unordered comparison can be lowered to a "flipped"
-    // comparison and a negation, and the negation can be merged into the
-    // select. Therefore, it not necessarily any more expensive than an
-    // ordered ("normal") comparison. Whether these optimizations will be
-    // performed is ultimately up to the backend, but at least x86 does
-    // perform them.
-    let s0 = bx.select(less_or_nan, int_min, fptosui_result);
-    let s1 = bx.select(greater, int_max, s0);
-
-    // Step 3: NaN replacement.
-    // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
-    // Therefore we only need to execute this step for signed integer types.
-    if signed {
-        // LLVM has no isNaN predicate, so we use (x == x) instead
-        let cmp = bx.fcmp(RealPredicate::RealOEQ, x, x);
-        bx.select(cmp, s1, zero)
-    } else {
-        s1
-    }
-}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 48d88095855..5a06fb46105 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -1,18 +1,21 @@
 use super::abi::AbiBuilderMethods;
 use super::asm::AsmBuilderMethods;
+use super::consts::ConstMethods;
 use super::coverageinfo::CoverageInfoBuilderMethods;
 use super::debuginfo::DebugInfoBuilderMethods;
 use super::intrinsic::IntrinsicCallMethods;
-use super::type_::ArgAbiMethods;
+use super::misc::MiscMethods;
+use super::type_::{ArgAbiMethods, BaseTypeMethods};
 use super::{HasCodegen, StaticBuilderMethods};
 
 use crate::common::{
-    AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope,
+    AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
 };
 use crate::mir::operand::OperandRef;
 use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 
+use rustc_apfloat::{ieee, Float, Round, Status};
 use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
@@ -202,6 +205,179 @@ pub trait BuilderMethods<'a, 'tcx>:
     fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value;
     fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
 
+    fn cast_float_to_int(
+        &mut self,
+        signed: bool,
+        x: Self::Value,
+        dest_ty: Self::Type,
+    ) -> Self::Value {
+        let in_ty = self.cx().val_ty(x);
+        let (float_ty, int_ty) = if self.cx().type_kind(dest_ty) == TypeKind::Vector
+            && self.cx().type_kind(in_ty) == TypeKind::Vector
+        {
+            (self.cx().element_type(in_ty), self.cx().element_type(dest_ty))
+        } else {
+            (in_ty, dest_ty)
+        };
+        assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double));
+        assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer);
+
+        if let Some(false) = self.cx().sess().opts.debugging_opts.saturating_float_casts {
+            return if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
+        }
+
+        let try_sat_result =
+            if signed { self.fptosi_sat(x, dest_ty) } else { self.fptoui_sat(x, dest_ty) };
+        if let Some(try_sat_result) = try_sat_result {
+            return try_sat_result;
+        }
+
+        let int_width = self.cx().int_width(int_ty);
+        let float_width = self.cx().float_width(float_ty);
+        // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
+        // destination integer type after rounding towards zero. This `undef` value can cause UB in
+        // safe code (see issue #10184), so we implement a saturating conversion on top of it:
+        // Semantically, the mathematical value of the input is rounded towards zero to the next
+        // mathematical integer, and then the result is clamped into the range of the destination
+        // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
+        // the destination integer type. NaN is mapped to 0.
+        //
+        // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
+        // a value representable in int_ty.
+        // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
+        // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
+        // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
+        // representable. Note that this only works if float_ty's exponent range is sufficiently large.
+        // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
+        // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
+        // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
+        // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
+        // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
+        let int_max = |signed: bool, int_width: u64| -> u128 {
+            let shift_amount = 128 - int_width;
+            if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
+        };
+        let int_min = |signed: bool, int_width: u64| -> i128 {
+            if signed { i128::MIN >> (128 - int_width) } else { 0 }
+        };
+
+        let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
+            let rounded_min =
+                ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+            assert_eq!(rounded_min.status, Status::OK);
+            let rounded_max =
+                ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+            assert!(rounded_max.value.is_finite());
+            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+        };
+        let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
+            let rounded_min =
+                ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+            assert_eq!(rounded_min.status, Status::OK);
+            let rounded_max =
+                ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+            assert!(rounded_max.value.is_finite());
+            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+        };
+        // To implement saturation, we perform the following steps:
+        //
+        // 1. Cast x to an integer with fpto[su]i. This may result in undef.
+        // 2. Compare x to f_min and f_max, and use the comparison results to select:
+        //  a) int_ty::MIN if x < f_min or x is NaN
+        //  b) int_ty::MAX if x > f_max
+        //  c) the result of fpto[su]i otherwise
+        // 3. If x is NaN, return 0.0, otherwise return the result of step 2.
+        //
+        // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
+        // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
+        // undef does not introduce any non-determinism either.
+        // More importantly, the above procedure correctly implements saturating conversion.
+        // Proof (sketch):
+        // If x is NaN, 0 is returned by definition.
+        // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
+        // This yields three cases to consider:
+        // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
+        //     saturating conversion for inputs in that range.
+        // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded
+        //     (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
+        //     than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX
+        //     is correct.
+        // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
+        //     int_ty::MIN and therefore the return value of int_ty::MIN is correct.
+        // QED.
+
+        let float_bits_to_llval = |bx: &mut Self, bits| {
+            let bits_llval = match float_width {
+                32 => bx.cx().const_u32(bits as u32),
+                64 => bx.cx().const_u64(bits as u64),
+                n => bug!("unsupported float width {}", n),
+            };
+            bx.bitcast(bits_llval, float_ty)
+        };
+        let (f_min, f_max) = match float_width {
+            32 => compute_clamp_bounds_single(signed, int_width),
+            64 => compute_clamp_bounds_double(signed, int_width),
+            n => bug!("unsupported float width {}", n),
+        };
+        let f_min = float_bits_to_llval(self, f_min);
+        let f_max = float_bits_to_llval(self, f_max);
+        let int_max = self.cx().const_uint_big(int_ty, int_max(signed, int_width));
+        let int_min = self.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
+        let zero = self.cx().const_uint(int_ty, 0);
+
+        // If we're working with vectors, constants must be "splatted": the constant is duplicated
+        // into each lane of the vector.  The algorithm stays the same, we are just using the
+        // same constant across all lanes.
+        let maybe_splat = |bx: &mut Self, val| {
+            if bx.cx().type_kind(dest_ty) == TypeKind::Vector {
+                bx.vector_splat(bx.vector_length(dest_ty), val)
+            } else {
+                val
+            }
+        };
+        let f_min = maybe_splat(self, f_min);
+        let f_max = maybe_splat(self, f_max);
+        let int_max = maybe_splat(self, int_max);
+        let int_min = maybe_splat(self, int_min);
+        let zero = maybe_splat(self, zero);
+
+        // Step 1 ...
+        let fptosui_result = if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
+        let less_or_nan = self.fcmp(RealPredicate::RealULT, x, f_min);
+        let greater = self.fcmp(RealPredicate::RealOGT, x, f_max);
+
+        // Step 2: We use two comparisons and two selects, with %s1 being the
+        // result:
+        //     %less_or_nan = fcmp ult %x, %f_min
+        //     %greater = fcmp olt %x, %f_max
+        //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
+        //     %s1 = select %greater, int_ty::MAX, %s0
+        // Note that %less_or_nan uses an *unordered* comparison. This
+        // comparison is true if the operands are not comparable (i.e., if x is
+        // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
+        // x is NaN.
+        //
+        // Performance note: Unordered comparison can be lowered to a "flipped"
+        // comparison and a negation, and the negation can be merged into the
+        // select. Therefore, it not necessarily any more expensive than an
+        // ordered ("normal") comparison. Whether these optimizations will be
+        // performed is ultimately up to the backend, but at least x86 does
+        // perform them.
+        let s0 = self.select(less_or_nan, int_min, fptosui_result);
+        let s1 = self.select(greater, int_max, s0);
+
+        // Step 3: NaN replacement.
+        // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
+        // Therefore we only need to execute this step for signed integer types.
+        if signed {
+            // LLVM has no isNaN predicate, so we use (x == x) instead
+            let cmp = self.fcmp(RealPredicate::RealOEQ, x, x);
+            self.select(cmp, s1, zero)
+        } else {
+            s1
+        }
+    }
+
     fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
     fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
 
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 3dde34a6410..6a3378a3896 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -3,7 +3,11 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use std::convert::TryInto;
 use std::ops::ControlFlow;
 
-/// Returns `true` if a used generic parameter requires substitution.
+/// Checks whether a type contains generic parameters which require substitution.
+///
+/// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization
+/// types may be "concrete enough" even though they still contain generic parameters in
+/// case these parameters are unused.
 crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
 where
     T: TypeFoldable<'tcx>,
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 694c679c158..19fa6812b45 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -645,9 +645,9 @@ impl RustcDefaultCalls {
         temps_dir: &Option<PathBuf>,
     ) -> Compilation {
         use rustc_session::config::PrintRequest::*;
-        // PrintRequest::NativeStaticLibs is special - printed during linking
+        // NativeStaticLibs and LinkArgs are special - printed during linking
         // (empty iterator returns true)
-        if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) {
+        if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
             return Compilation::Continue;
         }
 
@@ -738,7 +738,8 @@ impl RustcDefaultCalls {
                     codegen_backend.print(*req, sess);
                 }
                 // Any output here interferes with Cargo's parsing of other printed output
-                PrintRequest::NativeStaticLibs => {}
+                NativeStaticLibs => {}
+                LinkArgs => {}
             }
         }
         Compilation::Stop
diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md
index ca2eaa54057..584b78554ef 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0038.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0038.md
@@ -15,7 +15,7 @@ Two general aspects of trait object types give rise to the restrictions:
      these types can only be accessed through pointers, such as `&dyn Trait` or
      `Box<dyn Trait>`. The size of such a pointer is known, but the size of the
      `dyn Trait` object pointed-to by the pointer is _opaque_ to code working
-     with it, and different tait objects with the same trait object type may
+     with it, and different trait objects with the same trait object type may
      have different sizes.
 
   2. The pointer used to access a trait object is paired with an extra pointer
@@ -167,7 +167,7 @@ implementation on-demand. If you call `foo()` with a `bool` parameter, the
 compiler will only generate code for `foo::<bool>()`. When we have additional
 type parameters, the number of monomorphized implementations the compiler
 generates does not grow drastically, since the compiler will only generate an
-implementation if the function is called with unparametrized substitutions
+implementation if the function is called with unparameterized substitutions
 (i.e., substitutions where none of the substituted types are themselves
 parameterized).
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0183.md b/compiler/rustc_error_codes/src/error_codes/E0183.md
index 7e1d08daae1..92fa4c7c21e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0183.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0183.md
@@ -1,4 +1,4 @@
-Manual implemetation of a `Fn*` trait.
+Manual implementation of a `Fn*` trait.
 
 Erroneous code example:
 
@@ -33,7 +33,7 @@ impl FnOnce<()> for MyClosure {  // ok!
 }
 ```
 
-The argumements must be a tuple representing the argument list.
+The arguments must be a tuple representing the argument list.
 For more info, see the [tracking issue][iss29625]:
 
 [iss29625]: https://github.com/rust-lang/rust/issues/29625
diff --git a/compiler/rustc_error_codes/src/error_codes/E0521.md b/compiler/rustc_error_codes/src/error_codes/E0521.md
index 65dcac983ac..fedf6365fb5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0521.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0521.md
@@ -10,7 +10,7 @@ let _add = |el: &str| {
 };
 ```
 
-A type anotation of a closure parameter implies a new lifetime declaration.
+A type annotation of a closure parameter implies a new lifetime declaration.
 Consider to drop it, the compiler is reliably able to infer them.
 
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0581.md b/compiler/rustc_error_codes/src/error_codes/E0581.md
index 89f6e3269ec..02468dd9466 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0581.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0581.md
@@ -10,7 +10,7 @@ fn main() {
 }
 ```
 
-The problem here is that the lifetime isn't contrained by any of the arguments,
+The problem here is that the lifetime isn't constrained by any of the arguments,
 making it impossible to determine how long it's supposed to live.
 
 To fix this issue, either use the lifetime in the arguments, or use the
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index ebd12d6ab4e..0b65a5ff3ec 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -288,6 +288,8 @@ declare_features! (
     (active, asm_sym, "1.58.0", Some(72016), None),
     /// Allows the `may_unwind` option in inline assembly.
     (active, asm_unwind, "1.58.0", Some(72016), None),
+    /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
+    (active, associated_const_equality, "1.58.0", Some(92827), None),
     /// Allows the user of associated type bounds.
     (active, associated_type_bounds, "1.34.0", Some(52662), None),
     /// Allows associated type defaults.
@@ -413,7 +415,7 @@ declare_features! (
     // Allows setting the threshold for the `large_assignments` lint.
     (active, large_assignments, "1.52.0", Some(83518), None),
     /// Allows `if/while p && let q = r && ...` chains.
-    (incomplete, let_chains, "1.37.0", Some(53667), None),
+    (active, let_chains, "1.37.0", Some(53667), None),
     /// Allows `let...else` statements.
     (active, let_else, "1.56.0", Some(87335), None),
     /// Allows `#[link(..., cfg(..))]`.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 46817bc9c3f..723cc06864a 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -352,7 +352,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // Runtime
     ungated!(
-        windows_subsystem, Normal,
+        windows_subsystem, CrateLevel,
         template!(NameValueStr: "windows|console"), FutureWarnFollowing
     ),
     ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070
@@ -360,7 +360,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Code generation:
     ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing),
     ungated!(cold, Normal, template!(Word), WarnFollowing),
-    ungated!(no_builtins, Normal, template!(Word), WarnFollowing),
+    ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
     ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
     ungated!(track_caller, Normal, template!(Word), WarnFollowing),
     gated!(
@@ -682,6 +682,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
         from method dispatch when the receiver is an array, for compatibility in editions < 2021."
     ),
+    rustc_attr!(
+        rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing,
+        "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
+        definition of a trait, it's currently in experimental form and should be changed before \
+        being exposed outside of the std"
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index d813c887eee..e839f7fc777 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -449,13 +449,17 @@ impl Definitions {
     }
 
     #[inline(always)]
-    pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> LocalDefId {
+    pub fn local_def_path_hash_to_def_id(
+        &self,
+        hash: DefPathHash,
+        err: &mut dyn FnMut() -> !,
+    ) -> LocalDefId {
         debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
         self.table
             .def_path_hash_to_index
             .get(&hash)
             .map(|local_def_index| LocalDefId { local_def_index })
-            .unwrap()
+            .unwrap_or_else(|| err())
     }
 
     pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 369b5e6da2d..a9dbdd483fe 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -377,7 +377,7 @@ impl GenericArgs<'_> {
             GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
             _ => false,
         }) || self.bindings.iter().any(|arg| match arg.kind {
-            TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
+            TypeBindingKind::Equality { term: Term::Ty(ty) } => matches!(ty.kind, TyKind::Err),
             _ => false,
         })
     }
@@ -2129,19 +2129,37 @@ pub struct TypeBinding<'hir> {
     pub span: Span,
 }
 
+#[derive(Debug, HashStable_Generic)]
+pub enum Term<'hir> {
+    Ty(&'hir Ty<'hir>),
+    Const(AnonConst),
+}
+
+impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
+    fn from(ty: &'hir Ty<'hir>) -> Self {
+        Term::Ty(ty)
+    }
+}
+
+impl<'hir> From<AnonConst> for Term<'hir> {
+    fn from(c: AnonConst) -> Self {
+        Term::Const(c)
+    }
+}
+
 // Represents the two kinds of type bindings.
 #[derive(Debug, HashStable_Generic)]
 pub enum TypeBindingKind<'hir> {
     /// E.g., `Foo<Bar: Send>`.
     Constraint { bounds: &'hir [GenericBound<'hir>] },
-    /// E.g., `Foo<Bar = ()>`.
-    Equality { ty: &'hir Ty<'hir> },
+    /// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
+    Equality { term: Term<'hir> },
 }
 
 impl TypeBinding<'_> {
     pub fn ty(&self) -> &Ty<'_> {
         match self.kind {
-            TypeBindingKind::Equality { ref ty } => ty,
+            TypeBindingKind::Equality { term: Term::Ty(ref ty) } => ty,
             _ => panic!("expected equality type binding for parenthesized generic args"),
         }
     }
@@ -2708,6 +2726,10 @@ pub struct FnHeader {
 }
 
 impl FnHeader {
+    pub fn is_async(&self) -> bool {
+        matches!(&self.asyncness, IsAsync::Async)
+    }
+
     pub fn is_const(&self) -> bool {
         matches!(&self.constness, Constness::Const)
     }
@@ -3151,7 +3173,7 @@ impl<'hir> Node<'hir> {
         }
     }
 
-    pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
+    pub fn fn_decl(&self) -> Option<&'hir FnDecl<'hir>> {
         match self {
             Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
             | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
@@ -3163,6 +3185,15 @@ impl<'hir> Node<'hir> {
         }
     }
 
+    pub fn fn_sig(&self) -> Option<&'hir FnSig<'hir>> {
+        match self {
+            Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
+            | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
+            | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig),
+            _ => None,
+        }
+    }
+
     pub fn body_id(&self) -> Option<BodyId> {
         match self {
             Node::TraitItem(TraitItem {
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 6347a64fa85..cfdcd1618ba 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -801,12 +801,11 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
     visitor.visit_ident(type_binding.ident);
     visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
     match type_binding.kind {
-        TypeBindingKind::Equality { ref ty } => {
-            visitor.visit_ty(ty);
-        }
-        TypeBindingKind::Constraint { bounds } => {
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
+        TypeBindingKind::Equality { ref term } => match term {
+            Term::Ty(ref ty) => visitor.visit_ty(ty),
+            Term::Const(ref c) => visitor.visit_anon_const(c),
+        },
+        TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
     }
 }
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 7675778ff88..a301c5e3456 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -6,7 +6,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
 use rustc_ast_pretty::pp::{self, Breaks};
 use rustc_ast_pretty::pprust::{Comments, PrintState};
 use rustc_hir as hir;
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node};
+use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
 use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
 use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
@@ -1752,9 +1752,12 @@ impl<'a> State<'a> {
                 self.print_generic_args(binding.gen_args, false, false);
                 self.space();
                 match generic_args.bindings[0].kind {
-                    hir::TypeBindingKind::Equality { ref ty } => {
+                    hir::TypeBindingKind::Equality { ref term } => {
                         self.word_space("=");
-                        self.print_type(ty);
+                        match term {
+                            Term::Ty(ref ty) => self.print_type(ty),
+                            Term::Const(ref c) => self.print_anon_const(c),
+                        }
                     }
                     hir::TypeBindingKind::Constraint { bounds } => {
                         self.print_bounds(":", bounds);
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 392c5bdc15a..68180a2214a 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -190,7 +190,7 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
 
 fn rustc_version(nightly_build: bool) -> String {
     if nightly_build {
-        if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+        if let Some(val) = env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
             return val.to_string_lossy().into_owned();
         }
     }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 0e267179e30..9d40b3cba29 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -425,7 +425,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                         // FIXME: perf problem described in #55921.
                         ui = ty::UniverseIndex::ROOT;
                         return self.canonicalize_const_var(
-                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
+                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
                             ct,
                         );
                     }
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 0c26639e9b0..2d2edb07d9e 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -137,12 +137,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
             }
 
-            CanonicalVarKind::Const(ui) => self
+            CanonicalVarKind::Const(ui, ty) => self
                 .next_const_var_in_universe(
-                    self.next_ty_var_in_universe(
-                        TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span },
-                        universe_map(ui),
-                    ),
+                    ty,
                     ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
                     universe_map(ui),
                 )
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 6e6012fdc1a..14ab635a2ae 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -65,11 +65,11 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Item, ItemKind, Node};
 use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self,
+    error::TypeError,
     subst::{GenericArgKind, Subst, SubstsRef},
-    Region, Ty, TyCtxt, TypeFoldable,
+    Binder, Region, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
 use rustc_target::spec::abi;
@@ -1765,7 +1765,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.note_error_origin(diag, cause, exp_found, terr);
     }
 
-    pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
         if let ty::Opaque(def_id, substs) = ty.kind() {
             let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
             // Future::Output
@@ -1775,13 +1775,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
             for (predicate, _) in bounds {
                 let predicate = predicate.subst(self.tcx, substs);
-                if let ty::PredicateKind::Projection(projection_predicate) =
-                    predicate.kind().skip_binder()
-                {
-                    if projection_predicate.projection_ty.item_def_id == item_def_id {
-                        // We don't account for multiple `Future::Output = Ty` contraints.
-                        return Some(projection_predicate.ty);
-                    }
+                let output = predicate
+                    .kind()
+                    .map_bound(|kind| match kind {
+                        ty::PredicateKind::Projection(projection_predicate)
+                            if projection_predicate.projection_ty.item_def_id == item_def_id =>
+                        {
+                            projection_predicate.term.ty()
+                        }
+                        _ => None,
+                    })
+                    .transpose();
+                if output.is_some() {
+                    // We don't account for multiple `Future::Output = Ty` contraints.
+                    return output;
                 }
             }
         }
@@ -1823,8 +1830,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
 
         match (
-            self.get_impl_future_output_ty(exp_found.expected),
-            self.get_impl_future_output_ty(exp_found.found),
+            self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder),
+            self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder),
         ) {
             (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() {
                 ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index ac57796763f..4eec492b3ae 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -106,90 +106,47 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             None => String::new(),
         };
 
-        let (span_1, span_2, main_label, span_label, future_return_type) =
-            match (sup_is_ret_type, sub_is_ret_type) {
-                (None, None) => {
-                    let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
-                        (
-                            "this type is declared with multiple lifetimes...".to_owned(),
-                            "...but data with one lifetime flows into the other here".to_owned(),
-                        )
-                    } else {
-                        (
-                            "these two types are declared with different lifetimes...".to_owned(),
-                            format!("...but data{} flows{} here", span_label_var1, span_label_var2),
-                        )
-                    };
-                    (ty_sup.span, ty_sub.span, main_label_1, span_label_1, None)
-                }
+        debug!(
+            "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
+            sub_is_ret_type, sup_is_ret_type
+        );
 
-                (Some(ret_span), _) => {
-                    let sup_future = self.future_return_type(scope_def_id_sup);
-                    let (return_type, action) = if sup_future.is_some() {
-                        ("returned future", "held across an await point")
-                    } else {
-                        ("return type", "returned")
-                    };
+        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
 
-                    (
-                        ty_sub.span,
-                        ret_span,
-                        format!(
-                            "this parameter and the {} are declared with different lifetimes...",
-                            return_type
-                        ),
-                        format!("...but data{} is {} here", span_label_var1, action),
-                        sup_future,
-                    )
-                }
-                (_, Some(ret_span)) => {
-                    let sub_future = self.future_return_type(scope_def_id_sub);
-                    let (return_type, action) = if sub_future.is_some() {
-                        ("returned future", "held across an await point")
-                    } else {
-                        ("return type", "returned")
-                    };
+        match (sup_is_ret_type, sub_is_ret_type) {
+            (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
+                let param_span =
+                    if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
+
+                err.span_label(
+                    param_span,
+                    "this parameter and the return type are declared with different lifetimes...",
+                );
+                err.span_label(ret_span, "");
+                err.span_label(span, format!("...but data{} is returned here", span_label_var1));
+            }
 
-                    (
+            (None, None) => {
+                if ty_sup.hir_id == ty_sub.hir_id {
+                    err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
+                    err.span_label(ty_sub.span, "");
+                    err.span_label(span, "...but data with one lifetime flows into the other here");
+                } else {
+                    err.span_label(
                         ty_sup.span,
-                        ret_span,
-                        format!(
-                            "this parameter and the {} are declared with different lifetimes...",
-                            return_type
-                        ),
-                        format!("...but data{} is {} here", span_label_var1, action),
-                        sub_future,
-                    )
+                        "these two types are declared with different lifetimes...",
+                    );
+                    err.span_label(ty_sub.span, "");
+                    err.span_label(
+                        span,
+                        format!("...but data{} flows{} here", span_label_var1, span_label_var2),
+                    );
                 }
-            };
-
-        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
-
-        err.span_label(span_1, main_label);
-        err.span_label(span_2, String::new());
-        err.span_label(span, span_label);
+            }
+        }
 
         self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
 
-        if let Some(t) = future_return_type {
-            let snip = self
-                .tcx()
-                .sess
-                .source_map()
-                .span_to_snippet(t.span)
-                .ok()
-                .and_then(|s| match (&t.kind, s.as_str()) {
-                    (rustc_hir::TyKind::Tup(&[]), "") => Some("()".to_string()),
-                    (_, "") => None,
-                    _ => Some(s),
-                })
-                .unwrap_or_else(|| "{unnamed_type}".to_string());
-
-            err.span_label(
-                t.span,
-                &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
-            );
-        }
         err.emit();
         Some(ErrorReported)
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index 07bba000566..b1535701bb3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -1,6 +1,5 @@
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::Node;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime as rl;
@@ -25,25 +24,19 @@ pub(crate) fn find_anon_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     region: Region<'tcx>,
     br: &ty::BoundRegionKind,
-) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnDecl<'tcx>)> {
+) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
     if let Some(anon_reg) = tcx.is_suitable_region(region) {
         let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-        let fndecl = match tcx.hir().get(hir_id) {
-            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
-            | Node::TraitItem(&hir::TraitItem {
-                kind: hir::TraitItemKind::Fn(ref m, ..), ..
-            })
-            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => {
-                &m.decl
-            }
-            _ => return None,
+        let Some(fn_sig) = tcx.hir().get(hir_id).fn_sig() else {
+            return None
         };
 
-        fndecl
+        fn_sig
+            .decl
             .inputs
             .iter()
             .find_map(|arg| find_component_for_bound_region(tcx, arg, br))
-            .map(|ty| (ty, &**fndecl))
+            .map(|ty| (ty, fn_sig))
     } else {
         None
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 04eceecc5f0..6d71d702cc8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -4,7 +4,7 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::{self, DefIdTree, Region, Ty};
+use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
 use rustc_span::Span;
 
 /// Information about the anonymous region we are searching for.
@@ -94,80 +94,42 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             })
     }
 
-    pub(super) fn future_return_type(
-        &self,
-        local_def_id: LocalDefId,
-    ) -> Option<&rustc_hir::Ty<'_>> {
-        if let Some(hir::IsAsync::Async) = self.asyncness(local_def_id) {
-            if let rustc_middle::ty::Opaque(def_id, _) =
-                self.tcx().type_of(local_def_id).fn_sig(self.tcx()).output().skip_binder().kind()
-            {
-                match self.tcx().hir().get_if_local(*def_id) {
-                    Some(hir::Node::Item(hir::Item {
-                        kind:
-                            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                bounds,
-                                origin: hir::OpaqueTyOrigin::AsyncFn(..),
-                                ..
-                            }),
-                        ..
-                    })) => {
-                        for b in bounds.iter() {
-                            if let hir::GenericBound::LangItemTrait(
-                                hir::LangItem::Future,
-                                _span,
-                                _hir_id,
-                                generic_args,
-                            ) = b
-                            {
-                                for type_binding in generic_args.bindings.iter() {
-                                    if type_binding.ident.name == rustc_span::sym::Output {
-                                        if let hir::TypeBindingKind::Equality { ty } =
-                                            type_binding.kind
-                                        {
-                                            return Some(ty);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    _ => {}
-                }
-            }
-        }
-        None
-    }
-
-    pub(super) fn asyncness(&self, local_def_id: LocalDefId) -> Option<hir::IsAsync> {
-        // similar to the asyncness fn in rustc_ty_utils::ty
-        let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id);
-        let node = self.tcx().hir().get(hir_id);
-        let fn_kind = node.fn_kind()?;
-        Some(fn_kind.asyncness())
-    }
-
     // Here, we check for the case where the anonymous region
-    // is in the return type.
+    // is in the return type as written by the user.
     // FIXME(#42703) - Need to handle certain cases here.
     pub(super) fn is_return_type_anon(
         &self,
         scope_def_id: LocalDefId,
         br: ty::BoundRegionKind,
-        decl: &hir::FnDecl<'_>,
+        hir_sig: &hir::FnSig<'_>,
     ) -> Option<Span> {
-        let ret_ty = self.tcx().type_of(scope_def_id);
-        if let ty::FnDef(_, _) = ret_ty.kind() {
-            let sig = ret_ty.fn_sig(self.tcx());
-            let late_bound_regions =
-                self.tcx().collect_referenced_late_bound_regions(&sig.output());
-            if late_bound_regions.iter().any(|r| *r == br) {
-                return Some(decl.output.span());
-            }
+        let fn_ty = self.tcx().type_of(scope_def_id);
+        if let ty::FnDef(_, _) = fn_ty.kind() {
+            let ret_ty = fn_ty.fn_sig(self.tcx()).output();
+            let span = hir_sig.decl.output.span();
+            let future_output = if hir_sig.header.is_async() {
+                ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
+            } else {
+                None
+            };
+            return match future_output {
+                Some(output) if self.includes_region(output, br) => Some(span),
+                None if self.includes_region(ret_ty, br) => Some(span),
+                _ => None,
+            };
         }
         None
     }
 
+    fn includes_region(
+        &self,
+        ty: Binder<'tcx, impl TypeFoldable<'tcx>>,
+        region: ty::BoundRegionKind,
+    ) -> bool {
+        let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
+        late_bound_regions.iter().any(|r| *r == region)
+    }
+
     // Here we check for the case where anonymous region
     // corresponds to self and if yes, we display E0312.
     // FIXME(#42700) - Need to format self properly to
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 8894093c66c..4851e637d3a 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -584,8 +584,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
             debug!(?predicate);
 
             if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
-                if projection.ty.references_error() {
-                    // No point on adding these obligations since there's a type error involved.
+                if projection.term.references_error() {
                     return tcx.ty_error();
                 }
             }
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index 9b53ab72b00..b45a6514d79 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -26,7 +26,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             kind: TypeVariableOriginKind::NormalizeProjectionType,
             span: self.tcx.def_span(def_id),
         });
-        let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
+        let projection =
+            ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty_var.into() });
         let obligation = Obligation::with_depth(
             cause,
             recursion_depth,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 816e770f012..44acbd3cf21 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -646,6 +646,7 @@ fn test_debugging_options_tracking_hash() {
     untracked!(borrowck, String::from("other"));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
+    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
     untracked!(dump_mir, Some(String::from("abc")));
@@ -677,7 +678,6 @@ fn test_debugging_options_tracking_hash() {
     // `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
     untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
     untracked!(profile_closures, true);
-    untracked!(print_link_args, true);
     untracked!(print_llvm_passes, true);
     untracked!(print_mono_items, Some(String::from("abc")));
     untracked!(print_type_sizes, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index cb51555f5ca..3921187baa5 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -1,7 +1,7 @@
 use libloading::Library;
 use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
+use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Term};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[cfg(parallel_compiler)]
@@ -738,9 +738,14 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
                                         | ast::GenericArg::Const(_) => false,
                                     },
                                     ast::AngleBracketedArg::Constraint(c) => match c.kind {
-                                        ast::AssocTyConstraintKind::Bound { .. } => true,
-                                        ast::AssocTyConstraintKind::Equality { ref ty } => {
-                                            involves_impl_trait(ty)
+                                        ast::AssocConstraintKind::Bound { .. } => true,
+                                        ast::AssocConstraintKind::Equality { ref term } => {
+                                            match term {
+                                                Term::Ty(ty) => involves_impl_trait(ty),
+                                                // FIXME(...): This should check if the constant
+                                                // involves a trait impl, but for now ignore.
+                                                Term::Const(_) => false,
+                                            }
                                         }
                                     },
                                 })
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 66a89492abd..38e1669d331 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1247,7 +1247,7 @@ declare_lint! {
     /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
     MUTABLE_TRANSMUTES,
     Deny,
-    "mutating transmuted &mut T from &T may cause undefined behavior"
+    "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
 }
 
 declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
@@ -1259,8 +1259,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
         {
             if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
-                let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
-                               consider instead using an UnsafeCell";
+                let msg = "transmuting &T to &mut T is undefined behavior, \
+                    even if the reference is unused, consider instead using an UnsafeCell";
                 cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| lint.build(msg).emit());
             }
         }
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index f06fc3edf58..7030fd53704 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1168,25 +1168,6 @@ extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
   passes.run(*unwrap(M));
 }
 
-extern "C" void LLVMRustMarkAllFunctionsNounwind(LLVMModuleRef M) {
-  for (Module::iterator GV = unwrap(M)->begin(), E = unwrap(M)->end(); GV != E;
-       ++GV) {
-    GV->setDoesNotThrow();
-    Function *F = dyn_cast<Function>(GV);
-    if (F == nullptr)
-      continue;
-
-    for (Function::iterator B = F->begin(), BE = F->end(); B != BE; ++B) {
-      for (BasicBlock::iterator I = B->begin(), IE = B->end(); I != IE; ++I) {
-        if (isa<InvokeInst>(I)) {
-          InvokeInst *CI = cast<InvokeInst>(I);
-          CI->setDoesNotThrow();
-        }
-      }
-    }
-  }
-}
-
 extern "C" void
 LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module,
                                        LLVMTargetMachineRef TMR) {
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 639d2e617c7..13cd8e4a046 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -274,11 +274,6 @@ impl Collector<'_> {
                     span,
                     "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
                 );
-            } else if !self.tcx.sess.target.options.is_like_msvc {
-                self.tcx.sess.span_warn(
-                    span,
-                    "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu",
-                );
             }
 
             if lib_name.as_str().contains('\0') {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 39aa1844d69..220bc9c5f75 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -820,6 +820,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                     data.skip_array_during_method_dispatch,
                     data.specialization_kind,
                     self.def_path_hash(item_id),
+                    data.must_implement_one_of,
                 )
             }
             EntryKind::TraitAlias => ty::TraitDef::new(
@@ -831,6 +832,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 false,
                 ty::trait_def::TraitSpecializationKind::None,
                 self.def_path_hash(item_id),
+                None,
             ),
             _ => bug!("def-index does not refer to trait or trait alias"),
         }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index ee6656ce372..ebb78adf343 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1513,6 +1513,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     is_marker: trait_def.is_marker,
                     skip_array_during_method_dispatch: trait_def.skip_array_during_method_dispatch,
                     specialization_kind: trait_def.specialization_kind,
+                    must_implement_one_of: trait_def.must_implement_one_of.clone(),
                 };
 
                 EntryKind::Trait(self.lazy(data))
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 75c5880f05d..8424a31d59f 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -378,6 +378,7 @@ struct TraitData {
     is_marker: bool,
     skip_array_during_method_dispatch: bool,
     specialization_kind: ty::trait_def::TraitSpecializationKind,
+    must_implement_one_of: Option<Box<[Ident]>>,
 }
 
 #[derive(TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 30664784ed8..b1334410237 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -29,7 +29,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.75.0"
+chalk-ir = "0.76.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_session = { path = "../rustc_session" }
 rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 5c7cdbe4c2b..d20be0a34d2 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -266,7 +266,9 @@ impl DepNodeExt for DepNode {
     /// has been removed.
     fn extract_def_id<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
         if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
-            Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())))
+            Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
+                panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
+            }))
         } else {
             None
         }
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 605fff671db..28217aeab13 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -23,7 +23,7 @@
 
 use crate::infer::MemberConstraint;
 use crate::ty::subst::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, TyCtxt};
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use smallvec::SmallVec;
@@ -104,7 +104,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
             CanonicalVarKind::PlaceholderTy(_) => false,
             CanonicalVarKind::Region(_) => true,
             CanonicalVarKind::PlaceholderRegion(..) => false,
-            CanonicalVarKind::Const(_) => true,
+            CanonicalVarKind::Const(..) => true,
             CanonicalVarKind::PlaceholderConst(_) => false,
         }
     }
@@ -130,7 +130,7 @@ pub enum CanonicalVarKind<'tcx> {
     PlaceholderRegion(ty::PlaceholderRegion),
 
     /// Some kind of const inference variable.
-    Const(ty::UniverseIndex),
+    Const(ty::UniverseIndex, Ty<'tcx>),
 
     /// A "placeholder" that represents "any const".
     PlaceholderConst(ty::PlaceholderConst<'tcx>),
@@ -147,7 +147,7 @@ impl<'tcx> CanonicalVarKind<'tcx> {
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
-            CanonicalVarKind::Const(ui) => ui,
+            CanonicalVarKind::Const(ui, _) => ui,
             CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
         }
     }
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 39ca41c92ff..75dd223d014 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -308,7 +308,7 @@ pub struct ScopeTree {
     /// The reason is that semantically, until the `box` expression returns,
     /// the values are still owned by their containing expressions. So
     /// we'll see that `&x`.
-    pub yield_in_scope: FxHashMap<Scope, YieldData>,
+    pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>,
 
     /// The number of visit_expr and visit_pat calls done in the body.
     /// Used to sanity check visit_expr/visit_pat call count when
@@ -423,8 +423,8 @@ impl ScopeTree {
 
     /// Checks whether the given scope contains a `yield`. If so,
     /// returns `Some(YieldData)`. If not, returns `None`.
-    pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
-        self.yield_in_scope.get(&scope).cloned()
+    pub fn yield_in_scope(&self, scope: Scope) -> Option<&Vec<YieldData>> {
+        self.yield_in_scope.get(&scope)
     }
 
     /// Gives the number of expressions visited in a body.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 3f4bbdec315..48f39b26152 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -162,7 +162,7 @@ impl MirPhase {
 }
 
 /// Where a specific `mir::Body` comes from.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)]
 pub struct MirSource<'tcx> {
     pub instance: InstanceDef<'tcx>,
@@ -1255,17 +1255,7 @@ pub enum AssertKind<O> {
     ResumedAfterPanic(GeneratorKind),
 }
 
-#[derive(
-    Clone,
-    Debug,
-    PartialEq,
-    PartialOrd,
-    TyEncodable,
-    TyDecodable,
-    Hash,
-    HashStable,
-    TypeFoldable
-)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -1747,7 +1737,7 @@ pub struct CopyNonOverlapping<'tcx> {
 
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)]
 pub struct Place<'tcx> {
     pub local: Local,
 
@@ -2072,7 +2062,7 @@ pub struct SourceScopeLocalData {
 
 /// These are values that can appear inside an rvalue. They are intentionally
 /// limited to prevent rvalues from being nested in one another.
-#[derive(Clone, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum Operand<'tcx> {
     /// Copy: The value must be available for use afterwards.
     ///
@@ -2500,7 +2490,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 /// this does not necessarily mean that they are `==` in Rust. In
 /// particular, one must be wary of `NaN`!
 
-#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct Constant<'tcx> {
     pub span: Span,
 
@@ -2514,7 +2504,7 @@ pub struct Constant<'tcx> {
     pub literal: ConstantKind<'tcx>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
 #[derive(Lift)]
 pub enum ConstantKind<'tcx> {
     /// This constant came from the type system
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 51e4afaf220..fafd847a1cb 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -105,7 +105,7 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
 
 impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
 
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub enum TerminatorKind<'tcx> {
     /// Block should have one successor in the graph; we jump there.
     Goto { target: BasicBlock },
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index eef42666f2a..11dc69ab715 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -213,7 +213,7 @@ pub struct Expr<'tcx> {
 
 #[derive(Debug, HashStable)]
 pub enum ExprKind<'tcx> {
-    /// `Scope`s are used to explicitely mark destruction scopes,
+    /// `Scope`s are used to explicitly mark destruction scopes,
     /// and to track the `HirId` of the expressions within the scope.
     Scope {
         region_scope: region::Scope,
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 8563bac0bbf..2776370ba6f 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -152,6 +152,19 @@ impl<'tcx> AssocItems<'tcx> {
             .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
     }
 
+    /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
+    pub fn find_by_name_and_kinds(
+        &self,
+        tcx: TyCtxt<'_>,
+        ident: Ident,
+        kinds: &[AssocKind],
+        parent_def_id: DefId,
+    ) -> Option<&ty::AssocItem> {
+        self.filter_by_name_unhygienic(ident.name)
+            .filter(|item| kinds.contains(&item.kind))
+            .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+    }
+
     /// Returns the associated item with the given name in the given `Namespace`, if one exists.
     pub fn find_by_name_and_namespace(
         &self,
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 75705d40a6c..19a73732fca 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -36,6 +36,7 @@ impl<'tcx> Const<'tcx> {
         Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
     }
 
+    #[instrument(skip(tcx), level = "debug")]
     pub fn from_opt_const_arg_anon_const(
         tcx: TyCtxt<'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
@@ -51,6 +52,7 @@ impl<'tcx> Const<'tcx> {
         };
 
         let expr = &tcx.hir().body(body_id).value;
+        debug!(?expr);
 
         let ty = tcx.type_of(def.def_id_for_type_of());
 
@@ -67,11 +69,21 @@ impl<'tcx> Const<'tcx> {
         }
     }
 
+    #[instrument(skip(tcx), level = "debug")]
     fn try_eval_lit_or_param(
         tcx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Option<&'tcx Self> {
+        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+        let expr = match &expr.kind {
+            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+                block.expr.as_ref().unwrap()
+            }
+            _ => expr,
+        };
+
         let lit_input = match expr.kind {
             hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
             hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
@@ -86,22 +98,17 @@ impl<'tcx> Const<'tcx> {
         if let Some(lit_input) = lit_input {
             // If an error occurred, ignore that it's a literal and leave reporting the error up to
             // mir.
-            if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
-                return Some(c);
-            } else {
-                tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
+            match tcx.at(expr.span).lit_to_const(lit_input) {
+                Ok(c) => return Some(c),
+                Err(e) => {
+                    tcx.sess.delay_span_bug(
+                        expr.span,
+                        &format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
+                    );
+                }
             }
         }
 
-        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
-        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
-        let expr = match &expr.kind {
-            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
-                block.expr.as_ref().unwrap()
-            }
-            _ => expr,
-        };
-
         use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
         match expr.kind {
             ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e7b99995ca4..a7d7ee5efc8 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1210,11 +1210,25 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_ty(Error(DelaySpanBugEmitted(())))
     }
 
-    /// Like `err` but for constants.
+    /// Like [TyCtxt::ty_error] but for constants.
     #[track_caller]
     pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
-        self.sess
-            .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported.");
+        self.const_error_with_message(
+            ty,
+            DUMMY_SP,
+            "ty::ConstKind::Error constructed but no error reported",
+        )
+    }
+
+    /// Like [TyCtxt::ty_error_with_message] but for constants.
+    #[track_caller]
+    pub fn const_error_with_message<S: Into<MultiSpan>>(
+        self,
+        ty: Ty<'tcx>,
+        span: S,
+        msg: &str,
+    ) -> &'tcx Const<'tcx> {
+        self.sess.delay_span_bug(span, msg);
         self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
     }
 
@@ -1308,7 +1322,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
     /// session, if it still exists. This is used during incremental compilation to
     /// turn a deserialized `DefPathHash` into its current `DefId`.
-    pub fn def_path_hash_to_def_id(self, hash: DefPathHash) -> DefId {
+    pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() -> !) -> DefId {
         debug!("def_path_hash_to_def_id({:?})", hash);
 
         let stable_crate_id = hash.stable_crate_id();
@@ -1316,7 +1330,10 @@ impl<'tcx> TyCtxt<'tcx> {
         // If this is a DefPathHash from the local crate, we can look up the
         // DefId in the tcx's `Definitions`.
         if stable_crate_id == self.sess.local_stable_crate_id() {
-            self.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash).to_def_id()
+            self.untracked_resolutions
+                .definitions
+                .local_def_path_hash_to_def_id(hash, err)
+                .to_def_id()
         } else {
             // If this is a DefPathHash from an upstream crate, let the CrateStore map
             // it to a DefId.
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index a29a7d241e3..d68c5514821 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -4,7 +4,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::TyKind::*;
 use crate::ty::{
     ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
-    ProjectionTy, TyCtxt, TyS, TypeAndMut,
+    ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
 };
 
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -105,8 +105,14 @@ impl<'tcx> TyS<'tcx> {
                 ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
                     substs.iter().all(generic_arg_is_suggestible)
                 }
-                ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => {
-                    ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible)
+                ExistentialPredicate::Projection(ExistentialProjection {
+                    substs, term, ..
+                }) => {
+                    let term_is_suggestable = match term {
+                        Term::Ty(ty) => ty.is_suggestable(),
+                        Term::Const(c) => const_is_suggestable(c.val),
+                    };
+                    term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
                 }
                 _ => true,
             }),
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index b6e673983fd..f06a1b09cd8 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -1,5 +1,5 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, InferConst, Ty, TypeFlags};
+use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
 use std::slice;
 
 #[derive(Debug)]
@@ -241,9 +241,12 @@ impl FlagComputation {
                 self.add_ty(a);
                 self.add_ty(b);
             }
-            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
+            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
                 self.add_projection_ty(projection_ty);
-                self.add_ty(ty);
+                match term {
+                    Term::Ty(ty) => self.add_ty(ty),
+                    Term::Const(c) => self.add_const(c),
+                }
             }
             ty::PredicateKind::WellFormed(arg) => {
                 self.add_substs(slice::from_ref(&arg));
@@ -317,7 +320,10 @@ impl FlagComputation {
 
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
-        self.add_ty(projection.ty);
+        match projection.term {
+            ty::Term::Ty(ty) => self.add_ty(ty),
+            ty::Term::Const(ct) => self.add_const(ct),
+        }
     }
 
     fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index d6e89e52b95..4bc3e23f4a5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -484,7 +484,7 @@ crate struct PredicateInner<'tcx> {
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PredicateInner<'_>, 48);
+static_assert_size!(PredicateInner<'_>, 56);
 
 #[derive(Clone, Copy, Lift)]
 pub struct Predicate<'tcx> {
@@ -795,6 +795,31 @@ pub struct CoercePredicate<'tcx> {
 }
 pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable)]
+pub enum Term<'tcx> {
+    Ty(Ty<'tcx>),
+    Const(&'tcx Const<'tcx>),
+}
+
+impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
+    fn from(ty: Ty<'tcx>) -> Self {
+        Term::Ty(ty)
+    }
+}
+
+impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
+    fn from(c: &'tcx Const<'tcx>) -> Self {
+        Term::Const(c)
+    }
+}
+
+impl<'tcx> Term<'tcx> {
+    pub fn ty(&self) -> Option<Ty<'tcx>> {
+        if let Term::Ty(ty) = self { Some(ty) } else { None }
+    }
+}
+
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
 ///
@@ -811,7 +836,7 @@ pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 #[derive(HashStable, TypeFoldable)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
-    pub ty: Ty<'tcx>,
+    pub term: Term<'tcx>,
 }
 
 pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
@@ -836,8 +861,8 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
         self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
     }
 
-    pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> {
-        self.map_bound(|predicate| predicate.ty)
+    pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
+        self.map_bound(|predicate| predicate.term)
     }
 
     /// The `DefId` of the `TraitItem` for the associated type.
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 94cd650e39e..bbdaf248a9e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,6 +1,6 @@
 use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sso::SsoHashSet;
@@ -799,7 +799,7 @@ pub trait PrettyPrinter<'tcx>:
                     let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
 
                     // Projection type entry -- the def-id for naming, and the ty.
-                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
+                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
 
                     self.insert_trait_and_projection(
                         trait_ref,
@@ -850,8 +850,10 @@ pub trait PrettyPrinter<'tcx>:
                     }
 
                     p!(")");
-                    if !return_ty.skip_binder().is_unit() {
-                        p!("-> ", print(return_ty));
+                    if let Term::Ty(ty) = return_ty.skip_binder() {
+                        if !ty.is_unit() {
+                            p!("-> ", print(return_ty));
+                        }
                     }
                     p!(write("{}", if paren_needed { ")" } else { "" }));
 
@@ -902,23 +904,28 @@ pub trait PrettyPrinter<'tcx>:
                     first = false;
                 }
 
-                for (assoc_item_def_id, ty) in assoc_items {
+                for (assoc_item_def_id, term) in assoc_items {
                     if !first {
                         p!(", ");
                     }
                     p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
 
-                    // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
-                    match ty.skip_binder().kind() {
-                        ty::Projection(ty::ProjectionTy { item_def_id, .. })
-                            if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
-                        {
-                            p!("[async output]")
+                    match term.skip_binder() {
+                        Term::Ty(ty) => {
+                            // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
+                            if matches!(
+                              ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
+                              if Some(*item_def_id) == self.tcx().lang_items().generator_return()
+                            ) {
+                                p!("[async output]")
+                            } else {
+                                p!(print(ty))
+                            }
                         }
-                        _ => {
-                            p!(print(ty))
+                        Term::Const(c) => {
+                            p!(print(c));
                         }
-                    }
+                    };
 
                     first = false;
                 }
@@ -943,8 +950,11 @@ pub trait PrettyPrinter<'tcx>:
     fn insert_trait_and_projection(
         &mut self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
-        traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
+        proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
+        traits: &mut BTreeMap<
+            ty::PolyTraitRef<'tcx>,
+            BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
+        >,
         fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
     ) {
         let trait_def_id = trait_ref.def_id();
@@ -1019,7 +1029,11 @@ pub trait PrettyPrinter<'tcx>:
                         let mut projections = predicates.projection_bounds();
                         if let (Some(proj), None) = (projections.next(), projections.next()) {
                             let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
-                            p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty));
+                            p!(pretty_fn_sig(
+                                &tys,
+                                false,
+                                proj.skip_binder().term.ty().expect("Return type was a const")
+                            ));
                             resugared = true;
                         }
                     }
@@ -2442,7 +2456,7 @@ define_print_and_forward_display! {
 
     ty::ExistentialProjection<'tcx> {
         let name = cx.tcx().associated_item(self.item_def_id).ident;
-        p!(write("{} = ", name), print(self.ty))
+        p!(write("{} = ", name), print(self.term))
     }
 
     ty::ExistentialPredicate<'tcx> {
@@ -2499,7 +2513,14 @@ define_print_and_forward_display! {
     }
 
     ty::ProjectionPredicate<'tcx> {
-        p!(print(self.projection_ty), " == ", print(self.ty))
+        p!(print(self.projection_ty), " == ", print(self.term))
+    }
+
+    ty::Term<'tcx> {
+      match self {
+        ty::Term::Ty(ty) => p!(print(ty)),
+        ty::Term::Const(c) => p!(print(c)),
+      }
     }
 
     ty::ProjectionTy<'tcx> {
@@ -2709,5 +2730,5 @@ pub struct OpaqueFnEntry<'tcx> {
     has_fn_once: bool,
     fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
     fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
-    return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
+    return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
 }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 9e381cabdfe..bb040acd270 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -7,7 +7,7 @@
 use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
 use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
 use rustc_span::DUMMY_SP;
@@ -291,11 +291,11 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
                 b.item_def_id,
             )))
         } else {
-            let ty = relation.relate_with_variance(
+            let term = relation.relate_with_variance(
                 ty::Invariant,
                 ty::VarianceDiagInfo::default(),
-                a.ty,
-                b.ty,
+                a.term,
+                b.term,
             )?;
             let substs = relation.relate_with_variance(
                 ty::Invariant,
@@ -303,7 +303,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
                 a.substs,
                 b.substs,
             )?;
-            Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
+            Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
         }
     }
 }
@@ -833,6 +833,20 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
     }
 }
 
+impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: Self,
+        b: Self,
+    ) -> RelateResult<'tcx, Self> {
+        Ok(match (a, b) {
+            (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
+            (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+            _ => return Err(TypeError::Mismatch),
+        })
+    }
+}
+
 impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
@@ -841,7 +855,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
     ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
         Ok(ty::ProjectionPredicate {
             projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
-            ty: relation.relate(a.ty, b.ty)?,
+            term: relation.relate(a.term, b.term)?.into(),
         })
     }
 }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index a27169d59e1..1c5bc7860db 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -6,7 +6,7 @@ use crate::mir::interpret;
 use crate::mir::ProjectionKind;
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
-use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
@@ -158,7 +158,7 @@ impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.ty)
+        write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term)
     }
 }
 
@@ -356,6 +356,16 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
+    type Lifted = ty::Term<'tcx>;
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        Some(match self {
+            Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
+            Term::Const(c) => Term::Const(tcx.lift(c)?),
+        })
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
     type Lifted = ty::TraitPredicate<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
@@ -403,8 +413,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> {
 impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
     type Lifted = ty::ProjectionPredicate<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
-        tcx.lift((self.projection_ty, self.ty))
-            .map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty })
+        tcx.lift((self.projection_ty, self.term))
+            .map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term })
     }
 }
 
@@ -413,7 +423,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
             substs,
-            ty: tcx.lift(self.ty).expect("type must lift when substs do"),
+            term: tcx.lift(self.term).expect("type must lift when substs do"),
             item_def_id: self.item_def_id,
         })
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 92fb7612688..20db25f7899 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -8,7 +8,7 @@ use crate::infer::canonical::Canonical;
 use crate::ty::fold::ValidateBoundVars;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::InferTy::{self, *};
-use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
+use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable};
 use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
@@ -1540,7 +1540,7 @@ impl From<BoundVar> for BoundTy {
 pub struct ExistentialProjection<'tcx> {
     pub item_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
-    pub ty: Ty<'tcx>,
+    pub term: Term<'tcx>,
 }
 
 pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
@@ -1570,7 +1570,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
                 item_def_id: self.item_def_id,
                 substs: tcx.mk_substs_trait(self_ty, self.substs),
             },
-            ty: self.ty,
+            term: self.term,
         }
     }
 
@@ -1584,7 +1584,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
         Self {
             item_def_id: projection_predicate.projection_ty.item_def_id,
             substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
-            ty: projection_predicate.ty,
+            term: projection_predicate.term,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index ab33fbcca15..63e9b58584c 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -275,10 +275,6 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
         }
     }
 
-    pub fn is_noop(&self) -> bool {
-        self.is_empty()
-    }
-
     #[inline]
     pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
         self.iter()
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 34d059f4ec8..9f8053d4a4e 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,7 +1,7 @@
 use crate::traits::specialization_graph;
 use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
 use crate::ty::fold::TypeFoldable;
-use crate::ty::{Ty, TyCtxt};
+use crate::ty::{Ident, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::DefPathHash;
@@ -44,6 +44,10 @@ pub struct TraitDef {
     /// The ICH of this trait's DefPath, cached here so it doesn't have to be
     /// recomputed all the time.
     pub def_path_hash: DefPathHash,
+
+    /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which
+    /// must be implemented.
+    pub must_implement_one_of: Option<Box<[Ident]>>,
 }
 
 /// Whether this trait is treated specially by the standard library
@@ -87,6 +91,7 @@ impl<'tcx> TraitDef {
         skip_array_during_method_dispatch: bool,
         specialization_kind: TraitSpecializationKind,
         def_path_hash: DefPathHash,
+        must_implement_one_of: Option<Box<[Ident]>>,
     ) -> TraitDef {
         TraitDef {
             def_id,
@@ -97,6 +102,7 @@ impl<'tcx> TraitDef {
             skip_array_during_method_dispatch,
             specialization_kind,
             def_path_hash,
+            must_implement_one_of,
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 6808316a230..38aa7633385 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -157,7 +157,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                 stack.extend(obj.iter().rev().flat_map(|predicate| {
                     let (substs, opt_ty) = match predicate.skip_binder() {
                         ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
-                        ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
+                        ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.term)),
                         ty::ExistentialPredicate::AutoTrait(_) =>
                         // Empty iterator
                         {
@@ -165,7 +165,10 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                         }
                     };
 
-                    substs.iter().rev().chain(opt_ty.map(|ty| ty.into()))
+                    substs.iter().rev().chain(opt_ty.map(|term| match term {
+                        ty::Term::Ty(ty) => ty.into(),
+                        ty::Term::Const(ct) => ct.into(),
+                    }))
                 }));
             }
             ty::Adt(_, substs)
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 43060ecfced..da8fbdbf3bc 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -90,17 +90,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 };
 
                 let join_block = this.cfg.start_new_block();
-                this.cfg.terminate(
-                    then_blk,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-                this.cfg.terminate(
-                    else_blk,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-
+                this.cfg.goto(then_blk, source_info, join_block);
+                this.cfg.goto(else_blk, source_info, join_block);
                 join_block.unit()
             }
             ExprKind::Let { expr, ref pat } => {
@@ -109,8 +100,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.lower_let_expr(block, &this.thir[expr], pat, scope, expr_span)
                 });
 
-                let join_block = this.cfg.start_new_block();
-
                 this.cfg.push_assign_constant(
                     true_block,
                     source_info,
@@ -133,6 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     },
                 );
 
+                let join_block = this.cfg.start_new_block();
                 this.cfg.goto(true_block, source_info, join_block);
                 this.cfg.goto(false_block, source_info, join_block);
                 join_block.unit()
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index e3a05e01ea8..85950d82419 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -47,6 +47,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let expr_span = expr.span;
 
         match expr.kind {
+            ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
+                let lhs_then_block = unpack!(this.then_else_break(
+                    block,
+                    &this.thir[lhs],
+                    temp_scope_override,
+                    break_scope,
+                    variable_scope_span,
+                ));
+
+                let rhs_then_block = unpack!(this.then_else_break(
+                    lhs_then_block,
+                    &this.thir[rhs],
+                    temp_scope_override,
+                    break_scope,
+                    variable_scope_span,
+                ));
+
+                rhs_then_block.unit()
+            }
             ExprKind::Scope { region_scope, lint_level, value } => {
                 let region_scope = (region_scope, this.source_info(expr_span));
                 this.in_scope(region_scope, lint_level, |this| {
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index fc46c54c2fc..84d6c1d2db8 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -498,7 +498,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// if let Some(x) = a && let Some(y) = b && let Some(z) = c { ... }
     ///
-    /// there are three possible ways the condition can be false and we may have
+    /// There are three possible ways the condition can be false and we may have
     /// to drop `x`, `x` and `y`, or neither depending on which binding fails.
     /// To handle this correctly we use a `DropTree` in a similar way to a
     /// `loop` expression and 'break' out on all of the 'else' paths.
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 750677f161e..a43388808cd 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -315,7 +315,6 @@ impl<'tcx> Cx<'tcx> {
                             lhs: self.mirror_expr(lhs),
                             rhs: self.mirror_expr(rhs),
                         },
-
                         _ => {
                             let op = bin_op(op.node);
                             ExprKind::Binary {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 868dd195f3a..34204c3852a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -17,6 +17,7 @@ use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
 use rustc_session::Session;
+use rustc_span::source_map::Spanned;
 use rustc_span::{DesugaringKind, ExpnKind, Span};
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -445,6 +446,10 @@ fn check_let_reachability<'p, 'tcx>(
     pat: &'p DeconstructedPat<'p, 'tcx>,
     span: Span,
 ) {
+    if is_let_chain(cx.tcx, pat_id) {
+        return;
+    }
+
     let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
     let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
 
@@ -764,8 +769,11 @@ pub enum LetSource {
 
 fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
     let hir = tcx.hir();
+
     let parent = hir.get_parent_node(pat_id);
-    match hir.get(parent) {
+    let parent_node = hir.get(parent);
+
+    match parent_node {
         hir::Node::Arm(hir::Arm {
             guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
             ..
@@ -780,6 +788,7 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
         }
         _ => {}
     }
+
     let parent_parent = hir.get_parent_node(parent);
     let parent_parent_node = hir.get(parent_parent);
 
@@ -792,12 +801,30 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
         ..
     }) = parent_parent_parent_parent_node
     {
-        LetSource::WhileLet
-    } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) =
-        parent_parent_node
-    {
-        LetSource::IfLet
-    } else {
-        LetSource::GenericLet
+        return LetSource::WhileLet;
+    }
+
+    if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node {
+        return LetSource::IfLet;
     }
+
+    LetSource::GenericLet
+}
+
+// Since this function is called within a let context, it is reasonable to assume that any parent
+// `&&` infers a let chain
+fn is_let_chain(tcx: TyCtxt<'_>, pat_id: HirId) -> bool {
+    let hir = tcx.hir();
+    let parent = hir.get_parent_node(pat_id);
+    let parent_parent = hir.get_parent_node(parent);
+    matches!(
+        hir.get(parent_parent),
+        hir::Node::Expr(
+            hir::Expr {
+                kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, ..),
+                ..
+            },
+            ..
+        )
+    )
 }
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 77bc209539b..cda9ba9dcc8 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -3,8 +3,7 @@
 use crate::MirPass;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_middle::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets,
-    TerminatorKind,
+    BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, TerminatorKind,
 };
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -56,7 +55,10 @@ fn variant_discriminants<'tcx>(
     match &layout.variants {
         Variants::Single { index } => {
             let mut res = FxHashSet::default();
-            res.insert(index.as_u32() as u128);
+            res.insert(
+                ty.discriminant_for_variant(tcx, *index)
+                    .map_or(index.as_u32() as u128, |discr| discr.val),
+            );
             res
         }
         Variants::Multiple { variants, .. } => variants
@@ -75,16 +77,9 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if body.source.promoted.is_some() {
-            return;
-        }
-
         trace!("UninhabitedEnumBranching starting for {:?}", body.source);
 
-        let basic_block_count = body.basic_blocks().len();
-
-        for bb in 0..basic_block_count {
-            let bb = BasicBlock::from_usize(bb);
+        for bb in body.basic_blocks().indices() {
             trace!("processing block {:?}", bb);
 
             let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else {
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 7f8fadb33bd..48502112e3a 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -4,8 +4,8 @@ use crate::maybe_whole;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
 use rustc_ast::{
-    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
-    AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
+    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
+    AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
     Path, PathSegment, QSelf,
 };
 use rustc_errors::{pluralize, Applicability, PResult};
@@ -139,22 +139,46 @@ impl<'a> Parser<'a> {
         style: PathStyle,
         ty_generics: Option<&Generics>,
     ) -> PResult<'a, Path> {
-        maybe_whole!(self, NtPath, |path| {
+        let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| {
+            // Ensure generic arguments don't end up in attribute paths, such as:
+            //
+            //     macro_rules! m {
+            //         ($p:path) => { #[$p] struct S; }
+            //     }
+            //
+            //     m!(inline<u8>); //~ ERROR: unexpected generic arguments in path
+            //
             if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
             {
-                self.struct_span_err(
-                    path.segments
-                        .iter()
-                        .filter_map(|segment| segment.args.as_ref())
-                        .map(|arg| arg.span())
-                        .collect::<Vec<_>>(),
-                    "unexpected generic arguments in path",
-                )
-                .emit();
+                parser
+                    .struct_span_err(
+                        path.segments
+                            .iter()
+                            .filter_map(|segment| segment.args.as_ref())
+                            .map(|arg| arg.span())
+                            .collect::<Vec<_>>(),
+                        "unexpected generic arguments in path",
+                    )
+                    .emit();
             }
+        };
+
+        maybe_whole!(self, NtPath, |path| {
+            reject_generics_if_mod_style(self, &path);
             path
         });
 
+        if let token::Interpolated(nt) = &self.token.kind {
+            if let token::NtTy(ty) = &**nt {
+                if let ast::TyKind::Path(None, path) = &ty.kind {
+                    let path = path.clone();
+                    self.bump();
+                    reject_generics_if_mod_style(self, &path);
+                    return Ok(path);
+                }
+            }
+        }
+
         let lo = self.token.span;
         let mut segments = Vec::new();
         let mod_sep_ctxt = self.token.span.ctxt();
@@ -469,12 +493,9 @@ impl<'a> Parser<'a> {
                         // Parse associated type constraint bound.
 
                         let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
-                        AssocTyConstraintKind::Bound { bounds }
+                        AssocConstraintKind::Bound { bounds }
                     } else if self.eat(&token::Eq) {
-                        // Parse associated type equality constraint
-
-                        let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
-                        AssocTyConstraintKind::Equality { ty }
+                        self.parse_assoc_equality_term(ident, self.prev_token.span)?
                     } else {
                         unreachable!();
                     };
@@ -482,11 +503,11 @@ impl<'a> Parser<'a> {
                     let span = lo.to(self.prev_token.span);
 
                     // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
-                    if let AssocTyConstraintKind::Bound { .. } = kind {
+                    if let AssocConstraintKind::Bound { .. } = kind {
                         self.sess.gated_spans.gate(sym::associated_type_bounds, span);
                     }
                     let constraint =
-                        AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
+                        AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
                     Ok(Some(AngleBracketedArg::Constraint(constraint)))
                 } else {
                     Ok(Some(AngleBracketedArg::Arg(arg)))
@@ -499,22 +520,25 @@ impl<'a> Parser<'a> {
     /// Parse the term to the right of an associated item equality constraint.
     /// That is, parse `<term>` in `Item = <term>`.
     /// Right now, this only admits types in `<term>`.
-    fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
+    fn parse_assoc_equality_term(
+        &mut self,
+        ident: Ident,
+        eq: Span,
+    ) -> PResult<'a, AssocConstraintKind> {
         let arg = self.parse_generic_arg(None)?;
         let span = ident.span.to(self.prev_token.span);
-        match arg {
-            Some(GenericArg::Type(ty)) => return Ok(ty),
-            Some(GenericArg::Const(expr)) => {
-                self.struct_span_err(span, "cannot constrain an associated constant to a value")
-                    .span_label(ident.span, "this associated constant...")
-                    .span_label(expr.value.span, "...cannot be constrained to this value")
-                    .emit();
+        let term = match arg {
+            Some(GenericArg::Type(ty)) => ty.into(),
+            Some(GenericArg::Const(c)) => {
+                self.sess.gated_spans.gate(sym::associated_const_equality, span);
+                c.into()
             }
             Some(GenericArg::Lifetime(lt)) => {
                 self.struct_span_err(span, "associated lifetimes are not supported")
                     .span_label(lt.ident.span, "the lifetime is given here")
                     .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
                     .emit();
+                self.mk_ty(span, ast::TyKind::Err).into()
             }
             None => {
                 let after_eq = eq.shrink_to_hi();
@@ -542,8 +566,8 @@ impl<'a> Parser<'a> {
                 };
                 return Err(err);
             }
-        }
-        Ok(self.mk_ty(span, ast::TyKind::Err))
+        };
+        Ok(AssocConstraintKind::Equality { term })
     }
 
     /// We do not permit arbitrary expressions as const arguments. They must be one of:
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 9882d50ade1..c3d5bae32e6 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -126,6 +126,7 @@ impl CheckAttrVisitor<'_> {
             // lint-only checks
             match attr.name_or_empty() {
                 sym::cold => self.check_cold(hir_id, attr, span, target),
+                sym::link => self.check_link(hir_id, attr, span, target),
                 sym::link_name => self.check_link_name(hir_id, attr, span, target),
                 sym::link_section => self.check_link_section(hir_id, attr, span, target),
                 sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
@@ -1157,6 +1158,26 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    /// Checks if `#[link]` is applied to an item other than a foreign module.
+    fn check_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
+        match target {
+            Target::ForeignMod => {}
+            _ => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    let mut diag = lint.build("attribute should be applied to an `extern` block");
+                    diag.warn(
+                        "this was previously accepted by the compiler but is \
+                         being phased out; it will become a hard error in \
+                         a future release!",
+                    );
+
+                    diag.span_label(*span, "not an `extern` block");
+                    diag.emit();
+                });
+            }
+        }
+    }
+
     /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
     fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 4cca7142449..7f15aacc532 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -3,6 +3,7 @@
 // from live codes are live, and everything else is dead.
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,6 +16,7 @@ use rustc_middle::middle::privacy;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::lint;
 use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
 use std::mem;
 
 // Any local node that may call something in its body block should be
@@ -47,6 +49,10 @@ struct MarkSymbolVisitor<'tcx> {
     ignore_variant_stack: Vec<DefId>,
     // maps from tuple struct constructors to tuple struct items
     struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
+    // maps from ADTs to ignored derived traits (e.g. Debug and Clone)
+    // and the span of their respective impl (i.e., part of the derive
+    // macro)
+    ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
 }
 
 impl<'tcx> MarkSymbolVisitor<'tcx> {
@@ -242,7 +248,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     /// Automatically generated items marked with `rustc_trivial_field_reads`
     /// will be ignored for the purposes of dead code analysis (see PR #85200
     /// for discussion).
-    fn should_ignore_item(&self, def_id: DefId) -> bool {
+    fn should_ignore_item(&mut self, def_id: DefId) -> bool {
         if let Some(impl_of) = self.tcx.impl_of_method(def_id) {
             if !self.tcx.has_attr(impl_of, sym::automatically_derived) {
                 return false;
@@ -250,6 +256,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
 
             if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) {
                 if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
+                    let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+                    if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
+                        let impl_span = self.tcx.def_span(impl_of);
+                        if let Some(v) = self.ignored_derived_traits.get_mut(&adt_def.did) {
+                            v.push((impl_span, trait_of));
+                        } else {
+                            self.ignored_derived_traits
+                                .insert(adt_def.did, vec![(impl_span, trait_of)]);
+                        }
+                    }
                     return true;
                 }
             }
@@ -571,7 +587,7 @@ fn create_and_seed_worklist<'tcx>(
 fn find_live<'tcx>(
     tcx: TyCtxt<'tcx>,
     access_levels: &privacy::AccessLevels,
-) -> FxHashSet<LocalDefId> {
+) -> (FxHashSet<LocalDefId>, FxHashMap<DefId, Vec<(Span, DefId)>>) {
     let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels);
     let mut symbol_visitor = MarkSymbolVisitor {
         worklist,
@@ -584,14 +600,16 @@ fn find_live<'tcx>(
         pub_visibility: false,
         ignore_variant_stack: vec![],
         struct_constructors,
+        ignored_derived_traits: FxHashMap::default(),
     };
     symbol_visitor.mark_live_symbols();
-    symbol_visitor.live_symbols
+    (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
 }
 
 struct DeadVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     live_symbols: FxHashSet<LocalDefId>,
+    ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
 }
 
 impl<'tcx> DeadVisitor<'tcx> {
@@ -660,7 +678,37 @@ impl<'tcx> DeadVisitor<'tcx> {
             self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
                 let def_id = self.tcx.hir().local_def_id(id);
                 let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-                lint.build(&format!("{} is never {}: `{}`", descr, participle, name)).emit()
+                let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name));
+                let hir = self.tcx.hir();
+                if let Some(encl_scope) = hir.get_enclosing_scope(id) {
+                    if let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) {
+                        if let Some(ign_traits) =
+                            self.ignored_derived_traits.get(&encl_def_id.to_def_id())
+                        {
+                            let traits_str = ign_traits
+                                .iter()
+                                .map(|(_, t)| format!("`{}`", self.tcx.item_name(*t)))
+                                .collect::<Vec<_>>()
+                                .join(" and ");
+                            let plural_s = pluralize!(ign_traits.len());
+                            let article = if ign_traits.len() > 1 { "" } else { "a " };
+                            let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" };
+                            let msg = format!(
+                                "`{}` has {}derived impl{} for the trait{} {}, but {} \
+                                 intentionally ignored during dead code analysis",
+                                self.tcx.item_name(encl_def_id.to_def_id()),
+                                article,
+                                plural_s,
+                                plural_s,
+                                traits_str,
+                                is_are
+                            );
+                            let multispan = ign_traits.iter().map(|(s, _)| *s).collect::<Vec<_>>();
+                            err.span_note(multispan, &msg);
+                        }
+                    }
+                }
+                err.emit();
             });
         }
     }
@@ -790,7 +838,7 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let access_levels = &tcx.privacy_access_levels(());
-    let live_symbols = find_live(tcx, access_levels);
-    let mut visitor = DeadVisitor { tcx, live_symbols };
+    let (live_symbols, ignored_derived_traits) = find_live(tcx, access_levels);
+    let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
     tcx.hir().walk_toplevel_module(&mut visitor);
 }
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 5cc958ef549..6cf1aa480d2 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -332,9 +332,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_path_segment(self, path_span, path_segment)
     }
 
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
-        self.record("AssocTyConstraint", Id::None, constraint);
-        ast_visit::walk_assoc_ty_constraint(self, constraint)
+    fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
+        self.record("AssocConstraint", Id::None, constraint);
+        ast_visit::walk_assoc_constraint(self, constraint)
     }
 
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 85c568d8623..1031ba01c1b 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -294,9 +294,8 @@ impl<'tcx> ExprVisitor<'tcx> {
         // (!). In that case we still need the earlier check to verify that the
         // register class is usable at all.
         if let Some(feature) = feature {
-            let feat_sym = Symbol::intern(feature);
-            if !self.tcx.sess.target_features.contains(&feat_sym)
-                && !target_features.contains(&feat_sym)
+            if !self.tcx.sess.target_features.contains(&feature)
+                && !target_features.contains(&feature)
             {
                 let msg = &format!("`{}` target feature is not enabled", feature);
                 let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
@@ -377,9 +376,8 @@ impl<'tcx> ExprVisitor<'tcx> {
                     {
                         match feature {
                             Some(feature) => {
-                                let feat_sym = Symbol::intern(feature);
-                                if self.tcx.sess.target_features.contains(&feat_sym)
-                                    || attrs.target_features.contains(&feat_sym)
+                                if self.tcx.sess.target_features.contains(&feature)
+                                    || attrs.target_features.contains(&feature)
                                 {
                                     missing_required_features.clear();
                                     break;
@@ -413,7 +411,11 @@ impl<'tcx> ExprVisitor<'tcx> {
                             let msg = format!(
                                 "register class `{}` requires at least one of the following target features: {}",
                                 reg_class.name(),
-                                features.join(", ")
+                                features
+                                    .iter()
+                                    .map(|f| f.as_str())
+                                    .intersperse(", ")
+                                    .collect::<String>(),
                             );
                             self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
                             // register isn't enabled, don't do more checks
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 3596210036a..2075fee7171 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,6 +6,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(crate_visibility_modifier)]
+#![feature(iter_intersperse)]
 #![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index db699a56645..fdf93e58932 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -366,7 +366,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             let target_scopes = visitor.fixup_scopes.drain(start_point..);
 
             for scope in target_scopes {
-                let mut yield_data = visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap();
+                let mut yield_data =
+                    visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap();
                 let count = yield_data.expr_and_pat_count;
                 let span = yield_data.span;
 
@@ -429,7 +430,13 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             };
             let data =
                 YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source };
-            visitor.scope_tree.yield_in_scope.insert(scope, data);
+            match visitor.scope_tree.yield_in_scope.get_mut(&scope) {
+                Some(yields) => yields.push(data),
+                None => {
+                    visitor.scope_tree.yield_in_scope.insert(scope, vec![data]);
+                }
+            }
+
             if visitor.pessimistic_yield {
                 debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope);
                 visitor.fixup_scopes.push(scope);
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 7bee2ebf2f9..0b4579b299d 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -127,8 +127,8 @@ where
                 constness: _,
                 polarity: _,
             }) => self.visit_trait(trait_ref),
-            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
-                ty.visit_with(self)?;
+            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
+                term.visit_with(self)?;
                 self.visit_projection_ty(projection_ty)
             }
             ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
@@ -1148,19 +1148,11 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                 if self.visit(ty).is_break() {
                     return;
                 }
+            } else {
+                // We don't do anything for const infers here.
             }
         } else {
-            let local_id = self.tcx.hir().local_def_id(inf.hir_id);
-            if let Some(did) = self.tcx.opt_const_param_of(local_id) {
-                if self.visit_def_id(did, "inferred", &"").is_break() {
-                    return;
-                }
-            }
-
-            // FIXME see above note for same issue.
-            if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, &inf.to_ty())).is_break() {
-                return;
-            }
+            bug!("visit_infer without typeck_results");
         }
         intravisit::walk_inf(self, inf);
     }
@@ -1185,10 +1177,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
             }
 
             for (poly_predicate, _) in bounds.projection_bounds {
-                if self.visit(poly_predicate.skip_binder().ty).is_break()
-                    || self
-                        .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
-                        .is_break()
+                let pred = poly_predicate.skip_binder();
+                let poly_pred_term = self.visit(pred.term);
+                if poly_pred_term.is_break()
+                    || self.visit_projection_ty(pred.projection_ty).is_break()
                 {
                     return;
                 }
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 6a88e123537..5f6d9b050b2 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -761,7 +761,9 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        Ok(d.tcx().def_path_hash_to_def_id(def_path_hash))
+        Ok(d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || {
+            panic!("Failed to convert DefPathHash {:?}", def_path_hash)
+        }))
     }
 }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ccaaa2eaf46..2c678e71ae1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2517,6 +2517,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 self.visit_expr(elem);
                 self.resolve_anon_const(ct, IsRepeatExpr::Yes);
             }
+            ExprKind::Index(ref elem, ref idx) => {
+                self.resolve_expr(elem, Some(expr));
+                self.visit_expr(idx);
+            }
             _ => {
                 visit::walk_expr(self, expr);
             }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 4cd1b34bedc..7b4fe6f0e07 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -970,7 +970,13 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         };
 
         match (res, source) {
-            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+            (
+                Res::Def(DefKind::Macro(MacroKind::Bang), _),
+                PathSource::Expr(Some(Expr {
+                    kind: ExprKind::Index(..) | ExprKind::Call(..), ..
+                }))
+                | PathSource::Struct,
+            ) => {
                 err.span_label(span, fallback_label);
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
@@ -982,6 +988,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     err.note("if you want the `try` keyword, you need Rust 2018 or later");
                 }
             }
+            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+                err.span_label(span, fallback_label);
+            }
             (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
                 err.span_label(span, "type aliases cannot be used as traits");
                 if self.r.session.is_nightly_build() {
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 21cb93cc5f4..b95fe1b0549 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -821,9 +821,9 @@ impl<'tcx> SaveContext<'tcx> {
         let mut result = String::new();
 
         for attr in attrs {
-            if let Some(val) = attr.doc_str() {
+            if let Some((val, kind)) = attr.doc_str_and_comment_kind() {
                 // FIXME: Should save-analysis beautify doc strings itself or leave it to users?
-                result.push_str(beautify_doc_string(val).as_str());
+                result.push_str(beautify_doc_string(val, kind).as_str());
                 result.push('\n');
             }
         }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 62b351f5e02..92ad0723f48 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -565,6 +565,7 @@ pub enum PrintRequest {
     TargetSpec,
     NativeStaticLibs,
     StackProtectorStrategies,
+    LinkArgs,
 }
 
 #[derive(Copy, Clone)]
@@ -1187,7 +1188,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "Compiler information to print on stdout",
             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
              target-cpus|target-features|relocation-models|code-models|\
-             tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
+             tls-models|target-spec-json|native-static-libs|stack-protector-strategies\
+             link-args]",
         ),
         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1619,6 +1621,7 @@ fn collect_print_requests(
                 );
             }
         }
+        "link-args" => PrintRequest::LinkArgs,
         req => early_error(error_format, &format!("unknown print request `{}`", req)),
     }));
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 0b9623d1c7d..e7ab8fffdf3 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1161,6 +1161,8 @@ options! {
     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
         "print tasks that execute and the color their dep node gets (requires debug build) \
         (default: no)"),
+    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "import library generation tool (windows-gnu only)"),
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
         (default: no)"),
@@ -1337,8 +1339,6 @@ options! {
         See #77382 and #74551."),
     print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
         "make rustc print the total optimization fuel used by a crate"),
-    print_link_args: bool = (false, parse_bool, [UNTRACKED],
-        "print the arguments passed to the linker (default: no)"),
     print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
         "print the LLVM optimization passes being run (default: no)"),
     print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 0bba918994c..5390eed89fa 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -176,9 +176,9 @@ impl StableCrateId {
         // and no -Cmetadata, symbols from the same crate compiled with different versions of
         // rustc are named the same.
         //
-        // RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER is used to inject rustc version information
+        // RUSTC_FORCE_RUSTC_VERSION is used to inject rustc version information
         // during testing.
-        if let Some(val) = std::env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+        if let Some(val) = std::env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
             hasher.write(val.to_string_lossy().into_owned().as_bytes())
         } else {
             hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes());
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8020893e166..702e3594660 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -316,6 +316,7 @@ symbols! {
         allow_internal_unsafe,
         allow_internal_unstable,
         allowed,
+        alu32,
         always,
         and,
         and_then,
@@ -343,6 +344,7 @@ symbols! {
         assert_receiver_is_total_eq,
         assert_uninit_valid,
         assert_zero_valid,
+        associated_const_equality,
         associated_consts,
         associated_type_bounds,
         associated_type_defaults,
@@ -361,7 +363,10 @@ symbols! {
         augmented_assignments,
         auto_traits,
         automatically_derived,
+        avx,
         avx512_target_feature,
+        avx512bw,
+        avx512f,
         await_macro,
         bang,
         begin_panic,
@@ -592,6 +597,7 @@ symbols! {
         dylib,
         dyn_metadata,
         dyn_trait,
+        e,
         edition_macro_pats,
         edition_panic,
         eh_catch_typeinfo,
@@ -682,6 +688,7 @@ symbols! {
         format_args_macro,
         format_args_nl,
         format_macro,
+        fp,
         freeze,
         freg,
         frem_fast,
@@ -907,6 +914,7 @@ symbols! {
         neg,
         negate_unsigned,
         negative_impls,
+        neon,
         never,
         never_type,
         never_type_fallback,
@@ -1101,6 +1109,7 @@ symbols! {
         repr_packed,
         repr_simd,
         repr_transparent,
+        reserved_r9: "reserved-r9",
         residual,
         result,
         rhs,
@@ -1162,6 +1171,7 @@ symbols! {
         rustc_macro_transparency,
         rustc_main,
         rustc_mir,
+        rustc_must_implement_one_of,
         rustc_nonnull_optimization_guaranteed,
         rustc_object_lifetime_default,
         rustc_on_unimplemented,
@@ -1213,6 +1223,7 @@ symbols! {
         simd,
         simd_add,
         simd_and,
+        simd_as,
         simd_bitmask,
         simd_cast,
         simd_ceil,
@@ -1294,6 +1305,7 @@ symbols! {
         sqrtf64,
         sreg,
         sreg_low16,
+        sse,
         sse4a_target_feature,
         stable,
         staged_api,
@@ -1360,6 +1372,8 @@ symbols! {
         thread,
         thread_local,
         thread_local_macro,
+        thumb2,
+        thumb_mode: "thumb-mode",
         todo_macro,
         tool_attributes,
         tool_lints,
@@ -1453,6 +1467,7 @@ symbols! {
         vec,
         vec_macro,
         version,
+        vfp2,
         vis,
         visible_private_types,
         volatile,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 14e12bed59e..0d51f7779e1 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -559,7 +559,10 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                         let name = cx.tcx.associated_item(projection.item_def_id).ident;
                         cx.push("p");
                         cx.push_ident(name.as_str());
-                        cx = projection.ty.print(cx)?;
+                        cx = match projection.term {
+                            ty::Term::Ty(ty) => ty.print(cx),
+                            ty::Term::Const(c) => c.print(cx),
+                        }?;
                     }
                     ty::ExistentialPredicate::AutoTrait(def_id) => {
                         cx = cx.print_def_path(*def_id, &[])?;
@@ -769,9 +772,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
         disambiguated_data: &DisambiguatedDefPathData,
     ) -> Result<Self::Path, Self::Error> {
         let ns = match disambiguated_data.data {
-            // FIXME: It shouldn't be necessary to add anything for extern block segments,
-            // but we add 't' for backward compatibility.
-            DefPathData::ForeignMod => 't',
+            // Extern block segments can be skipped, names from extern blocks
+            // are effectively living in their parent modules.
+            DefPathData::ForeignMod => return print_prefix(self),
 
             // Uppercase categories are more stable than lowercase ones.
             DefPathData::TypeNs(_) => 't',
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 4bf909ce46d..da875508676 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -58,11 +60,11 @@ impl AArch64InlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
             Self::vreg | Self::vreg_low16 => types! {
-                "fp": I8, I16, I32, I64, F32, F64,
+                fp: I8, I16, I32, I64, F32, F64,
                     VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
                     VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
             },
@@ -73,7 +75,7 @@ impl AArch64InlineAsmRegClass {
 
 pub fn reserved_x18(
     _arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
     if target.os == "android"
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index b03594b3151..e3615b43c70 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
 use std::fmt;
 
 def_reg_class! {
@@ -44,31 +46,31 @@ impl ArmInlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, F32; },
-            Self::sreg | Self::sreg_low16 => types! { "vfp2": I32, F32; },
+            Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; },
             Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! {
-                "vfp2": I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
+                vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
             },
             Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
-                "neon": VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
+                neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
             },
         }
     }
 }
 
 // This uses the same logic as useR7AsFramePointer in LLVM
-fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
-    target.is_like_osx || (!target.is_like_windows && has_feature("thumb-mode"))
+fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) -> bool {
+    target.is_like_osx || (!target.is_like_windows && target_features.contains(&sym::thumb_mode))
 }
 
 fn frame_pointer_r11(
     _arch: InlineAsmArch,
-    has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
-    if !frame_pointer_is_r7(has_feature, target) {
+    if !frame_pointer_is_r7(target_features, target) {
         Err("the frame pointer (r11) cannot be used as an operand for inline asm")
     } else {
         Ok(())
@@ -77,10 +79,10 @@ fn frame_pointer_r11(
 
 fn frame_pointer_r7(
     _arch: InlineAsmArch,
-    has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
-    if frame_pointer_is_r7(has_feature, target) {
+    if frame_pointer_is_r7(target_features, target) {
         Err("the frame pointer (r7) cannot be used as an operand for inline asm")
     } else {
         Ok(())
@@ -89,10 +91,10 @@ fn frame_pointer_r7(
 
 fn not_thumb1(
     _arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
-    if has_feature("thumb-mode") && !has_feature("thumb2") {
+    if target_features.contains(&sym::thumb_mode) && !target_features.contains(&sym::thumb2) {
         Err("high registers (r8+) cannot be used in Thumb-1 code")
     } else {
         Ok(())
@@ -101,14 +103,14 @@ fn not_thumb1(
 
 fn reserved_r9(
     arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
-    not_thumb1(arch, &mut has_feature, target)?;
+    not_thumb1(arch, target_features, target)?;
 
     // We detect this using the reserved-r9 feature instead of using the target
     // because the relocation model can be changed with compiler options.
-    if has_feature("reserved-r9") {
+    if target_features.contains(&sym::reserved_r9) {
         Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
     } else {
         Ok(())
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
index 82a4f8bacb3..9a96a61f5b2 100644
--- a/compiler/rustc_target/src/asm/avr.rs
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -39,7 +40,7 @@ impl AvrInlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8; },
             Self::reg_upper => types! { _: I8; },
diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs
index ecb6bdc95ce..d94fcb53e24 100644
--- a/compiler/rustc_target/src/asm/bpf.rs
+++ b/compiler/rustc_target/src/asm/bpf.rs
@@ -1,5 +1,7 @@
 use super::{InlineAsmArch, InlineAsmType, Target};
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
 use std::fmt;
 
 def_reg_class! {
@@ -33,20 +35,20 @@ impl BpfInlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, I64; },
-            Self::wreg => types! { "alu32": I8, I16, I32; },
+            Self::wreg => types! { alu32: I8, I16, I32; },
         }
     }
 }
 
 fn only_alu32(
     _arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
-    if !has_feature("alu32") {
+    if !target_features.contains(&sym::alu32) {
         Err("register can't be used without the `alu32` target feature")
     } else {
         Ok(())
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
index 74afddb69dc..d20270ac9e9 100644
--- a/compiler/rustc_target/src/asm/hexagon.rs
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -32,7 +33,7 @@ impl HexagonInlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, F32; },
         }
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
index b19489aa439..b1e8737b52b 100644
--- a/compiler/rustc_target/src/asm/mips.rs
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -33,7 +34,7 @@ impl MipsInlineAsmRegClass {
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match (self, arch) {
             (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; },
             (Self::reg, _) => types! { _: I8, I16, I32, F32; },
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 9128e54682f..6b82bb337e6 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -81,14 +81,14 @@ macro_rules! def_regs {
 
             pub fn parse(
                 _arch: super::InlineAsmArch,
-                mut _has_feature: impl FnMut(&str) -> bool,
+                _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
                 _target: &crate::spec::Target,
                 name: &str,
             ) -> Result<Self, &'static str> {
                 match name {
                     $(
                         $($alias)|* | $reg_name => {
-                            $($filter(_arch, &mut _has_feature, _target)?;)?
+                            $($filter(_arch, _target_features, _target)?;)?
                             Ok(Self::$reg)
                         }
                     )*
@@ -102,7 +102,7 @@ macro_rules! def_regs {
 
         pub(super) fn fill_reg_map(
             _arch: super::InlineAsmArch,
-            mut _has_feature: impl FnMut(&str) -> bool,
+            _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
             _target: &crate::spec::Target,
             _map: &mut rustc_data_structures::fx::FxHashMap<
                 super::InlineAsmRegClass,
@@ -112,7 +112,7 @@ macro_rules! def_regs {
             #[allow(unused_imports)]
             use super::{InlineAsmReg, InlineAsmRegClass};
             $(
-                if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
+                if $($filter(_arch, _target_features, _target).is_ok() &&)? true {
                     if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
                         set.insert(InlineAsmReg::$arch($arch_reg::$reg));
                     }
@@ -130,7 +130,7 @@ macro_rules! def_regs {
 macro_rules! types {
     (
         $(_ : $($ty:expr),+;)?
-        $($feature:literal: $($ty2:expr),+;)*
+        $($feature:ident: $($ty2:expr),+;)*
     ) => {
         {
             use super::InlineAsmType::*;
@@ -139,7 +139,7 @@ macro_rules! types {
                     ($ty, None),
                 )*)?
                 $($(
-                    ($ty2, Some($feature)),
+                    ($ty2, Some(rustc_span::sym::$feature)),
                 )*)*
             ]
         }
@@ -289,7 +289,7 @@ impl InlineAsmReg {
 
     pub fn parse(
         arch: InlineAsmArch,
-        has_feature: impl FnMut(&str) -> bool,
+        target_features: &FxHashSet<Symbol>,
         target: &Target,
         name: Symbol,
     ) -> Result<Self, &'static str> {
@@ -298,43 +298,43 @@ impl InlineAsmReg {
         let name = name.as_str();
         Ok(match arch {
             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
-                Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::X86(X86InlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Arm => {
-                Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::AArch64 => {
-                Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::AArch64(AArch64InlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
-                Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::RiscV(RiscVInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Nvptx64 => {
-                Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Nvptx(NvptxInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
-                Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::PowerPC(PowerPCInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Hexagon => {
-                Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Hexagon(HexagonInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
-                Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Mips(MipsInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::S390x => {
-                Self::S390x(S390xInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::S390x(S390xInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::SpirV => {
-                Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::SpirV(SpirVInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
-                Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Wasm(WasmInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Bpf => {
-                Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Avr => {
-                Self::Avr(AvrInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?)
             }
         })
     }
@@ -510,7 +510,7 @@ impl InlineAsmRegClass {
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::X86(r) => r.supported_types(arch),
             Self::Arm(r) => r.supported_types(arch),
@@ -695,73 +695,73 @@ impl fmt::Display for InlineAsmType {
 // falling back to an external assembler.
 pub fn allocatable_registers(
     arch: InlineAsmArch,
-    has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &crate::spec::Target,
 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
     match arch {
         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
             let mut map = x86::regclass_map();
-            x86::fill_reg_map(arch, has_feature, target, &mut map);
+            x86::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Arm => {
             let mut map = arm::regclass_map();
-            arm::fill_reg_map(arch, has_feature, target, &mut map);
+            arm::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::AArch64 => {
             let mut map = aarch64::regclass_map();
-            aarch64::fill_reg_map(arch, has_feature, target, &mut map);
+            aarch64::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
             let mut map = riscv::regclass_map();
-            riscv::fill_reg_map(arch, has_feature, target, &mut map);
+            riscv::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Nvptx64 => {
             let mut map = nvptx::regclass_map();
-            nvptx::fill_reg_map(arch, has_feature, target, &mut map);
+            nvptx::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
             let mut map = powerpc::regclass_map();
-            powerpc::fill_reg_map(arch, has_feature, target, &mut map);
+            powerpc::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Hexagon => {
             let mut map = hexagon::regclass_map();
-            hexagon::fill_reg_map(arch, has_feature, target, &mut map);
+            hexagon::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
             let mut map = mips::regclass_map();
-            mips::fill_reg_map(arch, has_feature, target, &mut map);
+            mips::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::S390x => {
             let mut map = s390x::regclass_map();
-            s390x::fill_reg_map(arch, has_feature, target, &mut map);
+            s390x::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::SpirV => {
             let mut map = spirv::regclass_map();
-            spirv::fill_reg_map(arch, has_feature, target, &mut map);
+            spirv::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
             let mut map = wasm::regclass_map();
-            wasm::fill_reg_map(arch, has_feature, target, &mut map);
+            wasm::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Bpf => {
             let mut map = bpf::regclass_map();
-            bpf::fill_reg_map(arch, has_feature, target, &mut map);
+            bpf::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Avr => {
             let mut map = avr::regclass_map();
-            avr::fill_reg_map(arch, has_feature, target, &mut map);
+            avr::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
     }
@@ -794,7 +794,7 @@ impl InlineAsmClobberAbi {
     /// clobber ABIs for the target.
     pub fn parse(
         arch: InlineAsmArch,
-        has_feature: impl FnMut(&str) -> bool,
+        target_features: &FxHashSet<Symbol>,
         target: &Target,
         name: Symbol,
     ) -> Result<Self, &'static [&'static str]> {
@@ -819,7 +819,7 @@ impl InlineAsmClobberAbi {
             },
             InlineAsmArch::AArch64 => match name {
                 "C" | "system" | "efiapi" => {
-                    Ok(if aarch64::reserved_x18(arch, has_feature, target).is_err() {
+                    Ok(if aarch64::reserved_x18(arch, target_features, target).is_err() {
                         InlineAsmClobberAbi::AArch64NoX18
                     } else {
                         InlineAsmClobberAbi::AArch64
diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs
index 43d16ae0f5d..8e1e91e7c5f 100644
--- a/compiler/rustc_target/src/asm/nvptx.rs
+++ b/compiler/rustc_target/src/asm/nvptx.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 
 def_reg_class! {
     Nvptx NvptxInlineAsmRegClass {
@@ -33,7 +34,7 @@ impl NvptxInlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg16 => types! { _: I8, I16; },
             Self::reg32 => types! { _: I8, I16, I32, F32; },
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index 51a4303689e..d3ccb30350a 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -36,7 +37,7 @@ impl PowerPCInlineAsmRegClass {
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg | Self::reg_nonzero => {
                 if arch == InlineAsmArch::PowerPC {
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index 314bd01de12..39644d232ba 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
 use std::fmt;
 
 def_reg_class! {
@@ -35,7 +37,7 @@ impl RiscVInlineAsmRegClass {
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => {
                 if arch == InlineAsmArch::RiscV64 {
@@ -44,7 +46,7 @@ impl RiscVInlineAsmRegClass {
                     types! { _: I8, I16, I32, F32; }
                 }
             }
-            Self::freg => types! { "f": F32; "d": F64; },
+            Self::freg => types! { f: F32; d: F64; },
             Self::vreg => &[],
         }
     }
@@ -52,10 +54,10 @@ impl RiscVInlineAsmRegClass {
 
 fn not_e(
     _arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
-    if has_feature("e") {
+    if target_features.contains(&sym::e) {
         Err("register can't be used with the `e` target feature")
     } else {
         Ok(())
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index a74873f1747..0a50064f587 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -33,7 +34,7 @@ impl S390xInlineAsmRegClass {
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match (self, arch) {
             (Self::reg, _) => types! { _: I8, I16, I32, I64; },
             (Self::freg, _) => types! { _: F32, F64; },
diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs
index da82749e96a..31073da10b2 100644
--- a/compiler/rustc_target/src/asm/spirv.rs
+++ b/compiler/rustc_target/src/asm/spirv.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 
 def_reg_class! {
     SpirV SpirVInlineAsmRegClass {
@@ -31,7 +32,7 @@ impl SpirVInlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => {
                 types! { _: I8, I16, I32, I64, F32, F64; }
diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs
index 1b33f8f9632..f095b7c6e11 100644
--- a/compiler/rustc_target/src/asm/wasm.rs
+++ b/compiler/rustc_target/src/asm/wasm.rs
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 
 def_reg_class! {
     Wasm WasmInlineAsmRegClass {
@@ -31,7 +32,7 @@ impl WasmInlineAsmRegClass {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::local => {
                 types! { _: I8, I16, I32, I64, F32, F64; }
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 5e3828d7d85..01d32570f78 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -101,7 +103,7 @@ impl X86InlineAsmRegClass {
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg | Self::reg_abcd => {
                 if arch == InlineAsmArch::X86_64 {
@@ -112,23 +114,23 @@ impl X86InlineAsmRegClass {
             }
             Self::reg_byte => types! { _: I8; },
             Self::xmm_reg => types! {
-                "sse": I32, I64, F32, F64,
+                sse: I32, I64, F32, F64,
                   VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
             },
             Self::ymm_reg => types! {
-                "avx": I32, I64, F32, F64,
+                avx: I32, I64, F32, F64,
                     VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
                     VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4);
             },
             Self::zmm_reg => types! {
-                "avx512f": I32, I64, F32, F64,
+                avx512f: I32, I64, F32, F64,
                     VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
                     VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4),
                     VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8);
             },
             Self::kreg => types! {
-                "avx512f": I8, I16;
-                "avx512bw": I32, I64;
+                avx512f: I8, I16;
+                avx512bw: I32, I64;
             },
             Self::mmx_reg | Self::x87_reg => &[],
         }
@@ -137,7 +139,7 @@ impl X86InlineAsmRegClass {
 
 fn x86_64_only(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
@@ -149,7 +151,7 @@ fn x86_64_only(
 
 fn high_byte(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
@@ -160,7 +162,7 @@ fn high_byte(
 
 fn rbx_reserved(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
@@ -174,7 +176,7 @@ fn rbx_reserved(
 
 fn esi_reserved(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 05d2a373dc6..f2ed5ae26a3 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -6,7 +6,7 @@ use super::*;
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{Region, RegionVid, Term};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
@@ -606,7 +606,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     }
 
     fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
-        matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
+        if let Term::Ty(ty) = p.term().skip_binder() {
+            matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
+        } else {
+            false
+        }
     }
 
     fn evaluate_nested_obligations(
@@ -663,7 +667,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                     // Additionally, we check if we've seen this predicate before,
                     // to avoid rendering duplicate bounds to the user.
                     if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
-                        && !p.ty().skip_binder().has_infer_types()
+                        && !p.term().skip_binder().has_infer_types()
                         && is_new_pred
                     {
                         debug!(
@@ -752,7 +756,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // when we started out trying to unify
                             // some inference variables. See the comment above
                             // for more infomration
-                            if p.ty().skip_binder().has_infer_types() {
+                            if p.term().skip_binder().has_infer_types() {
                                 if !self.evaluate_nested_obligations(
                                     ty,
                                     v.into_iter(),
@@ -774,7 +778,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // However, we should always make progress (either by generating
                             // subobligations or getting an error) when we started off with
                             // inference variables
-                            if p.ty().skip_binder().has_infer_types() {
+                            if p.term().skip_binder().has_infer_types() {
                                 panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
                             }
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index d174e00df77..af3540386f9 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -53,6 +53,7 @@ pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) {
 /// If there are types that satisfy both impls, invokes `on_overlap`
 /// with a suitably-freshened `ImplHeader` with those types
 /// substituted. Otherwise, invokes `no_overlap`.
+#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")]
 pub fn overlapping_impls<F1, F2, R>(
     tcx: TyCtxt<'_>,
     impl1_def_id: DefId,
@@ -65,12 +66,6 @@ where
     F1: FnOnce(OverlapResult<'_>) -> R,
     F2: FnOnce() -> R,
 {
-    debug!(
-        "overlapping_impls(\
-           impl1_def_id={:?}, \
-           impl2_def_id={:?})",
-        impl1_def_id, impl2_def_id,
-    );
     // Before doing expensive operations like entering an inference context, do
     // a quick check via fast_reject to tell if the impl headers could possibly
     // unify.
@@ -85,6 +80,7 @@ where
     .any(|(ty1, ty2)| {
         let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No);
         let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No);
+
         if let (Some(t1), Some(t2)) = (t1, t2) {
             // Simplified successfully
             t1 != t2
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 d1958f85521..0760f626851 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1304,7 +1304,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
 
                 debug!(
                     "report_projection_error normalized_ty={:?} data.ty={:?}",
-                    normalized_ty, data.ty
+                    normalized_ty, data.term,
                 );
 
                 let is_normalized_ty_expected = !matches!(
@@ -1314,16 +1314,17 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         | ObligationCauseCode::ObjectCastObligation(_)
                         | ObligationCauseCode::OpaqueType
                 );
-
+                // FIXME(associated_const_equality): Handle Consts here
+                let data_ty = data.term.ty().unwrap();
                 if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
                     is_normalized_ty_expected,
                     normalized_ty,
-                    data.ty,
+                    data_ty,
                 ) {
                     values = Some(infer::ValuePairs::Types(ExpectedFound::new(
                         is_normalized_ty_expected,
                         normalized_ty,
-                        data.ty,
+                        data_ty,
                     )));
 
                     err_buf = error;
@@ -1803,11 +1804,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
             }
             ty::PredicateKind::Projection(data) => {
                 let self_ty = data.projection_ty.self_ty();
-                let ty = data.ty;
+                let term = data.term;
                 if predicate.references_error() || self.is_tainted_by_errors() {
                     return;
                 }
-                if self_ty.needs_infer() && ty.needs_infer() {
+                if self_ty.needs_infer() && term.needs_infer() {
                     // We do this for the `foo.collect()?` case to produce a suggestion.
                     let mut err = self.emit_inference_failure_err(
                         body_id,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 185d64eab70..7bfedecbdc7 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -571,7 +571,7 @@ fn object_ty_for_trait<'tcx>(
         // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
         super_trait_ref.map_bound(|super_trait_ref| {
             ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
+                term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
                 item_def_id: item.def_id,
                 substs: super_trait_ref.substs,
             })
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 577b96f3a40..f49f53351aa 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -212,10 +212,9 @@ fn project_and_unify_type<'cx, 'tcx>(
     debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
 
     let infcx = selcx.infcx();
-    match infcx
-        .at(&obligation.cause, obligation.param_env)
-        .eq(normalized_ty, obligation.predicate.ty)
-    {
+    // FIXME(associated_const_equality): Handle consts here as well as types.
+    let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
+    match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
             obligations.extend(inferred_obligations);
             Ok(Ok(Some(obligations)))
@@ -1615,7 +1614,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
                 substs: trait_ref.substs,
                 item_def_id: obligation.predicate.item_def_id,
             },
-            ty,
+            term: ty.into(),
         }
     });
 
@@ -1641,7 +1640,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
 
     let predicate = ty::ProjectionPredicate {
         projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
-        ty: self_ty.discriminant_ty(tcx),
+        term: self_ty.discriminant_ty(tcx).into(),
     };
 
     // We get here from `poly_project_and_unify_type` which replaces bound vars
@@ -1674,7 +1673,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
 
     let predicate = ty::ProjectionPredicate {
         projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
-        ty: metadata_ty,
+        term: metadata_ty.into(),
     };
 
     confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
@@ -1747,7 +1746,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
             substs: trait_ref.substs,
             item_def_id: fn_once_output_def_id,
         },
-        ty: ret_type,
+        term: ret_type.into(),
     });
 
     confirm_param_env_candidate(selcx, obligation, predicate, true)
@@ -1803,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
             assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
-            Progress { ty: cache_entry.ty, obligations: nested_obligations }
+            // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
+            // a term instead.
+            Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations }
         }
         Err(e) => {
             let msg = format!(
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
index e0098cc92d5..aea44841b8f 100644
--- a/compiler/rustc_trait_selection/src/traits/relationships.rs
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -62,7 +62,7 @@ pub(crate) fn update<'tcx, T>(
     if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
         // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
         // we need to make it into one.
-        if let Some(vid) = predicate.ty.ty_vid() {
+        if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
             debug!("relationship: {:?}.output = true", vid);
             engine.relationships().entry(vid).or_default().output = true;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index ab732f510ff..195a4a4a653 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -117,9 +117,8 @@ pub fn translate_substs<'a, 'tcx>(
 /// Specialization is determined by the sets of types to which the impls apply;
 /// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
 /// to.
+#[instrument(skip(tcx), level = "debug")]
 pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool {
-    debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
-
     // The feature gate should prevent introducing new specializations, but not
     // taking advantage of upstream ones.
     let features = tcx.features();
@@ -485,7 +484,7 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<St
     let mut types_without_default_bounds = FxHashSet::default();
     let sized_trait = tcx.lang_items().sized_trait();
 
-    if !substs.is_noop() {
+    if !substs.is_empty() {
         types_without_default_bounds.extend(substs.types());
         w.push('<');
         w.push_str(
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index f6e98f42710..6a355b567e0 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
         }
         ty::PredicateKind::Projection(t) => {
             wf.compute_projection(t.projection_ty);
-            wf.compute(t.ty.into());
+            wf.compute(match t.term {
+                ty::Term::Ty(ty) => ty.into(),
+                ty::Term::Const(c) => c.into(),
+            })
         }
         ty::PredicateKind::WellFormed(arg) => {
             wf.compute(arg);
@@ -219,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             // projection coming from another associated type. See
             // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
             // `traits-assoc-type-in-supertrait-bad.rs`.
-            if let ty::Projection(projection_ty) = proj.ty.kind() {
+            if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) {
                 if let Some(&impl_item_id) =
                     tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
                 {
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index f22751dc740..25f228c7890 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.75.0"
-chalk-engine = "0.75.0"
-chalk-solve = "0.75.0"
+chalk-ir = "0.76.0"
+chalk-engine = "0.76.0"
+chalk-solve = "0.76.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 36c536c0ba3..67d0ba39667 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -226,13 +226,26 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
     for rustc_middle::ty::ProjectionPredicate<'tcx>
 {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
+        // FIXME(associated_const_equality): teach chalk about terms for alias eq.
         chalk_ir::AliasEq {
-            ty: self.ty.lower_into(interner),
+            ty: self.term.ty().unwrap().lower_into(interner),
             alias: self.projection_ty.lower_into(interner),
         }
     }
 }
 
+/*
+// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere.
+impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> {
+  fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> {
+    match self {
+      ty::Term::Ty(ty) => ty.lower_into(interner).into(),
+      ty::Term::Const(c) => c.lower_into(interner).into(),
+    }
+  }
+}
+*/
+
 impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
         let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
@@ -651,7 +664,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
                                 .mk_substs_trait(self_ty, predicate.substs)
                                 .lower_into(interner),
                         }),
-                        ty: predicate.ty.lower_into(interner),
+                        // FIXME(associated_const_equality): teach chalk about terms for alias eq.
+                        ty: predicate.term.ty().unwrap().lower_into(interner),
                     }),
                 ),
                 ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
@@ -787,7 +801,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
             trait_bound: trait_ref.lower_into(interner),
             associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
             parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
-            value: self.ty.lower_into(interner),
+            value: self.term.ty().unwrap().lower_into(interner),
         }
     }
 }
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index a4d844e2eb8..09bfdabf473 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -85,7 +85,7 @@ crate fn evaluate_goal<'tcx>(
                         chalk_ir::VariableKind::Lifetime,
                         chalk_ir::UniverseIndex { counter: ui.index() },
                     ),
-                    CanonicalVarKind::Const(_ui) => unimplemented!(),
+                    CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
                     CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
                 }),
             ),
@@ -127,9 +127,9 @@ crate fn evaluate_goal<'tcx>(
                     chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
                         ty::UniverseIndex::from_usize(var.skip_kind().counter),
                     ),
-                    chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
-                        ty::UniverseIndex::from_usize(var.skip_kind().counter),
-                    ),
+                    // FIXME(compiler-errors): We don't currently have a way of turning
+                    // a Chalk ty back into a rustc ty, right?
+                    chalk_ir::VariableKind::Const(_) => todo!(),
                 };
                 CanonicalVarInfo { kind }
             })
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index 7e570e151c5..57930a28a35 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -15,6 +15,7 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_target = { path = "../rustc_target" }
@@ -27,3 +28,4 @@ rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
 rustc_lint = { path = "../rustc_lint" }
+rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index 1f99a9b0536..b532c41642c 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -151,8 +151,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .bindings
                     .iter()
                     .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
-                        (true, hir::TypeBindingKind::Equality { ty }) => {
-                            sess.source_map().span_to_snippet(ty.span).ok()
+                        (true, hir::TypeBindingKind::Equality { term }) => {
+                            let span = match term {
+                                hir::Term::Ty(ty) => ty.span,
+                                hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
+                            };
+                            sess.source_map().span_to_snippet(span).ok()
                         }
                         _ => None,
                     })
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 2ada1c0ddf4..d9b3f51b5bd 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -6,7 +6,7 @@ mod errors;
 mod generics;
 
 use crate::bounds::Bounds;
-use crate::collect::PlaceholderHirTyCollector;
+use crate::collect::HirPlaceholderCollector;
 use crate::errors::{
     AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits,
     TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified,
@@ -123,7 +123,7 @@ struct ConvertedBinding<'a, 'tcx> {
 
 #[derive(Debug)]
 enum ConvertedBindingKind<'a, 'tcx> {
-    Equality(Ty<'tcx>),
+    Equality(ty::Term<'tcx>),
     Constraint(&'a [hir::GenericBound<'a>]),
 }
 
@@ -601,10 +601,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .iter()
             .map(|binding| {
                 let kind = match binding.kind {
-                    hir::TypeBindingKind::Equality { ty } => {
-                        ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
-                    }
-                    hir::TypeBindingKind::Constraint { bounds } => {
+                    hir::TypeBindingKind::Equality { ref term } => match term {
+                        hir::Term::Ty(ref ty) => {
+                            ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
+                        }
+                        hir::Term::Const(ref c) => {
+                            let local_did = self.tcx().hir().local_def_id(c.hir_id);
+                            let c = Const::from_anon_const(self.tcx(), local_did);
+                            ConvertedBindingKind::Equality(c.into())
+                        }
+                    },
+                    hir::TypeBindingKind::Constraint { ref bounds } => {
                         ConvertedBindingKind::Constraint(bounds)
                     }
                 };
@@ -867,6 +874,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
             .is_some()
     }
+    fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+        self.tcx()
+            .associated_items(trait_def_id)
+            .find_by_name_and_kinds(
+                self.tcx(),
+                assoc_name,
+                &[ty::AssocKind::Type, ty::AssocKind::Const],
+                trait_def_id,
+            )
+            .is_some()
+    }
 
     // Sets `implicitly_sized` to true on `Bounds` if necessary
     pub(crate) fn add_implicitly_sized<'hir>(
@@ -1118,9 +1136,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .associated_items(candidate.def_id())
             .filter_by_name_unhygienic(assoc_ident.name)
             .find(|i| {
-                i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
+                (i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
+                    && i.ident.normalize_to_macros_2_0() == assoc_ident
             })
             .expect("missing associated type");
+        // FIXME(associated_const_equality): need to handle assoc_consts here as well.
+        if assoc_ty.kind == ty::AssocKind::Const {
+            tcx.sess
+                .struct_span_err(path_span, &format!("associated const equality is incomplete"))
+                .span_label(path_span, "cannot yet relate associated const")
+                .emit();
+            return Err(ErrorReported);
+        }
 
         if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
             tcx.sess
@@ -1215,18 +1242,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
 
         match binding.kind {
-            ConvertedBindingKind::Equality(ty) => {
+            ConvertedBindingKind::Equality(term) => {
                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
                 // the "projection predicate" for:
                 //
                 // `<T as Iterator>::Item = u32`
                 bounds.projection_bounds.push((
-                    projection_ty.map_bound(|projection_ty| {
-                        debug!(
-                            "add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
-                            projection_ty, projection_ty.substs
-                        );
-                        ty::ProjectionPredicate { projection_ty, ty }
+                    projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
+                        projection_ty,
+                        term: term,
                     }),
                     binding.span,
                 ));
@@ -1377,8 +1401,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         let pred = bound_predicate.rebind(pred);
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
-                        let references_self =
-                            pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
+                        let references_self = match pred.skip_binder().term {
+                            ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+                            ty::Term::Const(c) => c.ty.walk().any(|arg| arg == dummy_self.into()),
+                        };
 
                         // If the projection output contains `Self`, force the user to
                         // elaborate it explicitly to avoid a lot of complexity.
@@ -1601,7 +1627,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
     {
         let mut matching_candidates = all_candidates()
-            .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
+            .filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
 
         let bound = match matching_candidates.next() {
             Some(bound) => bound,
@@ -2478,7 +2504,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         debug!(?bound_vars);
 
         // We proactively collect all the inferred type params to emit a single error per fn def.
-        let mut visitor = PlaceholderHirTyCollector::default();
+        let mut visitor = HirPlaceholderCollector::default();
         for ty in decl.inputs {
             visitor.visit_ty(ty);
         }
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 8bc3a48e5b5..6a28bb16a20 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -48,14 +48,19 @@ impl<'tcx> Bounds<'tcx> {
     /// where-clauses). Because some of our bounds listings (e.g.,
     /// regions) don't include the self-type, you must supply the
     /// self-type here (the `param_ty` parameter).
-    pub fn predicates(
-        &self,
+    pub fn predicates<'out, 's>(
+        &'s self,
         tcx: TyCtxt<'tcx>,
         param_ty: Ty<'tcx>,
-    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+        // the output must live shorter than the duration of the borrow of self and 'tcx.
+    ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
+    where
+        'tcx: 'out,
+        's: 'out,
+    {
         // If it could be sized, and is, add the `Sized` predicate.
         let sized_predicate = self.implicitly_sized.and_then(|span| {
-            tcx.lang_items().sized_trait().map(|sized| {
+            tcx.lang_items().sized_trait().map(move |sized| {
                 let trait_ref = ty::Binder::dummy(ty::TraitRef {
                     def_id: sized,
                     substs: tcx.mk_substs_trait(param_ty, &[]),
@@ -64,25 +69,22 @@ impl<'tcx> Bounds<'tcx> {
             })
         });
 
-        sized_predicate
-            .into_iter()
-            .chain(self.region_bounds.iter().map(|&(region_bound, span)| {
-                (
-                    region_bound
-                        .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
-                        .to_predicate(tcx),
-                    span,
-                )
-            }))
-            .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
+        let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
+            let pred = region_bound
+                .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
+                .to_predicate(tcx);
+            (pred, span)
+        });
+        let trait_bounds =
+            self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
                 let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
                 (predicate, span)
-            }))
-            .chain(
-                self.projection_bounds
-                    .iter()
-                    .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
-            )
-            .collect()
+            });
+        let projection_bounds = self
+            .projection_bounds
+            .iter()
+            .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
+
+        sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
     }
 }
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 7a3d5990329..eb49cc0233d 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -978,6 +978,10 @@ fn check_impl_items_against_trait<'tcx>(
     if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
         // Check for missing items from trait
         let mut missing_items = Vec::new();
+
+        let mut must_implement_one_of: Option<&[Ident]> =
+            trait_def.must_implement_one_of.as_deref();
+
         for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
             let is_implemented = ancestors
                 .leaf_def(tcx, trait_item_id)
@@ -986,12 +990,37 @@ fn check_impl_items_against_trait<'tcx>(
             if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
                 missing_items.push(tcx.associated_item(trait_item_id));
             }
+
+            if let Some(required_items) = &must_implement_one_of {
+                // true if this item is specifically implemented in this impl
+                let is_implemented_here = ancestors
+                    .leaf_def(tcx, trait_item_id)
+                    .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+
+                if is_implemented_here {
+                    let trait_item = tcx.associated_item(trait_item_id);
+                    if required_items.contains(&trait_item.ident) {
+                        must_implement_one_of = None;
+                    }
+                }
+            }
         }
 
         if !missing_items.is_empty() {
             let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
             missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
         }
+
+        if let Some(missing_items) = must_implement_one_of {
+            let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
+            let attr_span = tcx
+                .get_attrs(impl_trait_ref.def_id)
+                .iter()
+                .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+                .map(|attr| attr.span);
+
+            missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
+        }
     }
 }
 
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index c87ab0d410c..e88099afa03 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -279,7 +279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return None;
         };
 
-        let ret_param_ty = projection.skip_binder().ty;
+        // Since this is a return parameter type it is safe to unwrap.
+        let ret_param_ty = projection.skip_binder().term.ty().unwrap();
         let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
         debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
 
@@ -706,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Extract the type from the projection. Note that there can
         // be no bound variables in this type because the "self type"
         // does not have any regions in it.
-        let output_ty = self.resolve_vars_if_possible(predicate.ty);
+        let output_ty = self.resolve_vars_if_possible(predicate.term);
         debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
-        Some(output_ty)
+        // This is a projection on a Fn trait so will always be a type.
+        Some(output_ty.ty().unwrap())
     }
 
     /// Converts the types that the user supplied, in case that doing
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 3984d8b7425..94648d5702c 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -1353,7 +1353,7 @@ pub fn check_type_bounds<'tcx>(
                             item_def_id: trait_ty.def_id,
                             substs: rebased_substs,
                         },
-                        ty: impl_ty_value,
+                        term: impl_ty_value.into(),
                     },
                     bound_vars,
                 )
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 3e73cc659ec..f6abeff60cd 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1909,7 +1909,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => return,
         };
         let mut add_label = true;
-        if let ty::Adt(def, _) = output_ty.kind() {
+        if let ty::Adt(def, _) = output_ty.skip_binder().kind() {
             // no field access on enum type
             if !def.is_enum() {
                 if def
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index a031f802b6d..f01b8267817 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // `foo.bar::<u32>(...)` -- the `Self` type here will be the
         // type of `foo` (possibly adjusted), but we don't want to
         // include that. We want just the `[_, u32]` part.
-        if !method.substs.is_noop() {
+        if !method.substs.is_empty() {
             let method_generics = self.tcx.generics_of(method.def_id);
             if !method_generics.params.is_empty() {
                 let user_type_annotation = self.infcx.probe(|_| {
@@ -211,7 +211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
-        if !substs.is_noop() {
+        if !substs.is_empty() {
             debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
 
             self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 473c848ad8f..be4c9ec99b9 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -609,14 +609,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
             let ty = self.normalize_associated_types_in(expr.span, ty);
             let ty = match self.tcx.asyncness(fn_id.owner) {
-                hir::IsAsync::Async => self.tcx.infer_ctxt().enter(|infcx| {
-                    infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
-                        span_bug!(
-                            fn_decl.output.span(),
-                            "failed to get output type of async function"
-                        )
+                hir::IsAsync::Async => self
+                    .tcx
+                    .infer_ctxt()
+                    .enter(|infcx| {
+                        infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+                            span_bug!(
+                                fn_decl.output.span(),
+                                "failed to get output type of async function"
+                            )
+                        })
                     })
-                }),
+                    .skip_binder(),
                 hir::IsAsync::NotAsync => ty,
             };
             if self.can_coerce(found, ty) {
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index fb6e11dbfb7..56b6dd9a284 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -3,6 +3,7 @@
 //! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
 //! types computed here.
 
+use self::drop_ranges::DropRanges;
 use super::FnCtxt;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::pluralize;
@@ -19,6 +20,8 @@ use rustc_span::Span;
 use smallvec::SmallVec;
 use tracing::debug;
 
+mod drop_ranges;
+
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
@@ -34,6 +37,7 @@ struct InteriorVisitor<'a, 'tcx> {
     guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
     guard_bindings_set: HirIdSet,
     linted_values: HirIdSet,
+    drop_ranges: DropRanges,
 }
 
 impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
@@ -48,9 +52,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
     ) {
         use rustc_span::DUMMY_SP;
 
+        let ty = self.fcx.resolve_vars_if_possible(ty);
+
         debug!(
-            "generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
-            ty, scope, expr, source_span
+            "attempting to record type ty={:?}; hir_id={:?}; scope={:?}; expr={:?}; source_span={:?}; expr_count={:?}",
+            ty, hir_id, scope, expr, source_span, self.expr_count,
         );
 
         let live_across_yield = scope
@@ -63,21 +69,27 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                     //
                     // See the mega-comment at `yield_in_scope` for a proof.
 
-                    debug!(
-                        "comparing counts yield: {} self: {}, source_span = {:?}",
-                        yield_data.expr_and_pat_count, self.expr_count, source_span
-                    );
+                    yield_data
+                        .iter()
+                        .find(|yield_data| {
+                            debug!(
+                                "comparing counts yield: {} self: {}, source_span = {:?}",
+                                yield_data.expr_and_pat_count, self.expr_count, source_span
+                            );
+
+                            if self.drop_ranges.is_dropped_at(hir_id, yield_data.expr_and_pat_count)
+                            {
+                                debug!("value is dropped at yield point; not recording");
+                                return false;
+                            }
 
-                    // If it is a borrowing happening in the guard,
-                    // it needs to be recorded regardless because they
-                    // do live across this yield point.
-                    if guard_borrowing_from_pattern
-                        || yield_data.expr_and_pat_count >= self.expr_count
-                    {
-                        Some(yield_data)
-                    } else {
-                        None
-                    }
+                            // If it is a borrowing happening in the guard,
+                            // it needs to be recorded regardless because they
+                            // do live across this yield point.
+                            guard_borrowing_from_pattern
+                                || yield_data.expr_and_pat_count >= self.expr_count
+                        })
+                        .cloned()
                 })
             })
             .unwrap_or_else(|| {
@@ -85,7 +97,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
             });
 
         if let Some(yield_data) = live_across_yield {
-            let ty = self.fcx.resolve_vars_if_possible(ty);
             debug!(
                 "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
                 expr, scope, ty, self.expr_count, yield_data.span
@@ -154,7 +165,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                 self.expr_count,
                 expr.map(|e| e.span)
             );
-            let ty = self.fcx.resolve_vars_if_possible(ty);
             if let Some((unresolved_type, unresolved_type_span)) =
                 self.fcx.unresolved_type_vars(&ty)
             {
@@ -186,6 +196,7 @@ pub fn resolve_interior<'a, 'tcx>(
         guard_bindings: <_>::default(),
         guard_bindings_set: <_>::default(),
         linted_values: <_>::default(),
+        drop_ranges: drop_ranges::compute_drop_ranges(fcx, def_id, body),
     };
     intravisit::walk_body(&mut visitor, body);
 
@@ -313,6 +324,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         let mut guard_borrowing_from_pattern = false;
+
         match &expr.kind {
             ExprKind::Call(callee, args) => match &callee.kind {
                 ExprKind::Path(qpath) => {
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
new file mode 100644
index 00000000000..21a8d7b5634
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
@@ -0,0 +1,269 @@
+//! Drop range analysis finds the portions of the tree where a value is guaranteed to be dropped
+//! (i.e. moved, uninitialized, etc.). This is used to exclude the types of those values from the
+//! generator type. See `InteriorVisitor::record` for where the results of this analysis are used.
+//!
+//! There are three phases to this analysis:
+//! 1. Use `ExprUseVisitor` to identify the interesting values that are consumed and borrowed.
+//! 2. Use `DropRangeVisitor` to find where the interesting values are dropped or reinitialized,
+//!    and also build a control flow graph.
+//! 3. Use `DropRanges::propagate_to_fixpoint` to flow the dropped/reinitialized information through
+//!    the CFG and find the exact points where we know a value is definitely dropped.
+//!
+//! The end result is a data structure that maps the post-order index of each node in the HIR tree
+//! to a set of values that are known to be dropped at that location.
+
+use self::cfg_build::build_control_flow_graph;
+use self::record_consumed_borrow::find_consumed_and_borrowed;
+use crate::check::FnCtxt;
+use hir::def_id::DefId;
+use hir::{Body, HirId, HirIdMap, Node};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::hir::map::Map;
+use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
+use rustc_middle::ty;
+use std::collections::BTreeMap;
+use std::fmt::Debug;
+
+mod cfg_build;
+mod cfg_propagate;
+mod cfg_visualize;
+mod record_consumed_borrow;
+
+pub fn compute_drop_ranges<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    def_id: DefId,
+    body: &'tcx Body<'tcx>,
+) -> DropRanges {
+    let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
+
+    let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
+    let mut drop_ranges = build_control_flow_graph(
+        fcx.tcx.hir(),
+        fcx.tcx,
+        &fcx.typeck_results.borrow(),
+        consumed_borrowed_places,
+        body,
+        num_exprs,
+    );
+
+    drop_ranges.propagate_to_fixpoint();
+
+    DropRanges { tracked_value_map: drop_ranges.tracked_value_map, nodes: drop_ranges.nodes }
+}
+
+/// Applies `f` to consumable node in the HIR subtree pointed to by `place`.
+///
+/// This includes the place itself, and if the place is a reference to a local
+/// variable then `f` is also called on the HIR node for that variable as well.
+///
+/// For example, if `place` points to `foo()`, then `f` is called once for the
+/// result of `foo`. On the other hand, if `place` points to `x` then `f` will
+/// be called both on the `ExprKind::Path` node that represents the expression
+/// as well as the HirId of the local `x` itself.
+fn for_each_consumable<'tcx>(hir: Map<'tcx>, place: TrackedValue, mut f: impl FnMut(TrackedValue)) {
+    f(place);
+    let node = hir.find(place.hir_id());
+    if let Some(Node::Expr(expr)) = node {
+        match expr.kind {
+            hir::ExprKind::Path(hir::QPath::Resolved(
+                _,
+                hir::Path { res: hir::def::Res::Local(hir_id), .. },
+            )) => {
+                f(TrackedValue::Variable(*hir_id));
+            }
+            _ => (),
+        }
+    }
+}
+
+rustc_index::newtype_index! {
+    pub struct PostOrderId {
+        DEBUG_FORMAT = "id({})",
+    }
+}
+
+rustc_index::newtype_index! {
+    pub struct TrackedValueIndex {
+        DEBUG_FORMAT = "hidx({})",
+    }
+}
+
+/// Identifies a value whose drop state we need to track.
+#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
+enum TrackedValue {
+    /// Represents a named variable, such as a let binding, parameter, or upvar.
+    ///
+    /// The HirId points to the variable's definition site.
+    Variable(HirId),
+    /// A value produced as a result of an expression.
+    ///
+    /// The HirId points to the expression that returns this value.
+    Temporary(HirId),
+}
+
+impl TrackedValue {
+    fn hir_id(&self) -> HirId {
+        match self {
+            TrackedValue::Variable(hir_id) | TrackedValue::Temporary(hir_id) => *hir_id,
+        }
+    }
+}
+
+/// Represents a reason why we might not be able to convert a HirId or Place
+/// into a tracked value.
+#[derive(Debug)]
+enum TrackedValueConversionError {
+    /// Place projects are not currently supported.
+    ///
+    /// The reasoning around these is kind of subtle, so we choose to be more
+    /// conservative around these for now. There is not reason in theory we
+    /// cannot support these, we just have not implemented it yet.
+    PlaceProjectionsNotSupported,
+}
+
+impl TryFrom<&PlaceWithHirId<'_>> for TrackedValue {
+    type Error = TrackedValueConversionError;
+
+    fn try_from(place_with_id: &PlaceWithHirId<'_>) -> Result<Self, Self::Error> {
+        if !place_with_id.place.projections.is_empty() {
+            debug!(
+                "TrackedValue from PlaceWithHirId: {:?} has projections, which are not supported.",
+                place_with_id
+            );
+            return Err(TrackedValueConversionError::PlaceProjectionsNotSupported);
+        }
+
+        match place_with_id.place.base {
+            PlaceBase::Rvalue | PlaceBase::StaticItem => {
+                Ok(TrackedValue::Temporary(place_with_id.hir_id))
+            }
+            PlaceBase::Local(hir_id)
+            | PlaceBase::Upvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id }, .. }) => {
+                Ok(TrackedValue::Variable(hir_id))
+            }
+        }
+    }
+}
+
+pub struct DropRanges {
+    tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+    nodes: IndexVec<PostOrderId, NodeInfo>,
+}
+
+impl DropRanges {
+    pub fn is_dropped_at(&self, hir_id: HirId, location: usize) -> bool {
+        self.tracked_value_map
+            .get(&TrackedValue::Temporary(hir_id))
+            .or(self.tracked_value_map.get(&TrackedValue::Variable(hir_id)))
+            .cloned()
+            .map_or(false, |tracked_value_id| {
+                self.expect_node(location.into()).drop_state.contains(tracked_value_id)
+            })
+    }
+
+    /// Returns a reference to the NodeInfo for a node, panicking if it does not exist
+    fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
+        &self.nodes[id]
+    }
+}
+
+/// Tracks information needed to compute drop ranges.
+struct DropRangesBuilder {
+    /// The core of DropRangesBuilder is a set of nodes, which each represent
+    /// one expression. We primarily refer to them by their index in a
+    /// post-order traversal of the HIR tree,  since this is what
+    /// generator_interior uses to talk about yield positions.
+    ///
+    /// This IndexVec keeps the relevant details for each node. See the
+    /// NodeInfo struct for more details, but this information includes things
+    /// such as the set of control-flow successors, which variables are dropped
+    /// or reinitialized, and whether each variable has been inferred to be
+    /// known-dropped or potentially reintiialized at each point.
+    nodes: IndexVec<PostOrderId, NodeInfo>,
+    /// We refer to values whose drop state we are tracking by the HirId of
+    /// where they are defined. Within a NodeInfo, however, we store the
+    /// drop-state in a bit vector indexed by a HirIdIndex
+    /// (see NodeInfo::drop_state). The hir_id_map field stores the mapping
+    /// from HirIds to the HirIdIndex that is used to represent that value in
+    /// bitvector.
+    tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+
+    /// When building the control flow graph, we don't always know the
+    /// post-order index of the target node at the point we encounter it.
+    /// For example, this happens with break and continue. In those cases,
+    /// we store a pair of the PostOrderId of the source and the HirId
+    /// of the target. Once we have gathered all of these edges, we make a
+    /// pass over the set of deferred edges (see process_deferred_edges in
+    /// cfg_build.rs), look up the PostOrderId for the target (since now the
+    /// post-order index for all nodes is known), and add missing control flow
+    /// edges.
+    deferred_edges: Vec<(PostOrderId, HirId)>,
+    /// This maps HirIds of expressions to their post-order index. It is
+    /// used in process_deferred_edges to correctly add back-edges.
+    post_order_map: HirIdMap<PostOrderId>,
+}
+
+impl Debug for DropRangesBuilder {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("DropRanges")
+            .field("hir_id_map", &self.tracked_value_map)
+            .field("post_order_maps", &self.post_order_map)
+            .field("nodes", &self.nodes.iter_enumerated().collect::<BTreeMap<_, _>>())
+            .finish()
+    }
+}
+
+/// DropRanges keeps track of what values are definitely dropped at each point in the code.
+///
+/// Values of interest are defined by the hir_id of their place. Locations in code are identified
+/// by their index in the post-order traversal. At its core, DropRanges maps
+/// (hir_id, post_order_id) -> bool, where a true value indicates that the value is definitely
+/// dropped at the point of the node identified by post_order_id.
+impl DropRangesBuilder {
+    /// Returns the number of values (hir_ids) that are tracked
+    fn num_values(&self) -> usize {
+        self.tracked_value_map.len()
+    }
+
+    fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo {
+        let size = self.num_values();
+        self.nodes.ensure_contains_elem(id, || NodeInfo::new(size));
+        &mut self.nodes[id]
+    }
+
+    fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
+        trace!("adding control edge from {:?} to {:?}", from, to);
+        self.node_mut(from.into()).successors.push(to.into());
+    }
+}
+
+#[derive(Debug)]
+struct NodeInfo {
+    /// IDs of nodes that can follow this one in the control flow
+    ///
+    /// If the vec is empty, then control proceeds to the next node.
+    successors: Vec<PostOrderId>,
+
+    /// List of hir_ids that are dropped by this node.
+    drops: Vec<TrackedValueIndex>,
+
+    /// List of hir_ids that are reinitialized by this node.
+    reinits: Vec<TrackedValueIndex>,
+
+    /// Set of values that are definitely dropped at this point.
+    drop_state: BitSet<TrackedValueIndex>,
+}
+
+impl NodeInfo {
+    fn new(num_values: usize) -> Self {
+        Self {
+            successors: vec![],
+            drops: vec![],
+            reinits: vec![],
+            drop_state: BitSet::new_filled(num_values),
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
new file mode 100644
index 00000000000..fc957b89990
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -0,0 +1,473 @@
+use super::{
+    for_each_consumable, record_consumed_borrow::ConsumedAndBorrowedPlaces, DropRangesBuilder,
+    NodeInfo, PostOrderId, TrackedValue, TrackedValueIndex,
+};
+use hir::{
+    intravisit::{self, Visitor},
+    Body, Expr, ExprKind, Guard, HirId,
+};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_index::vec::IndexVec;
+use rustc_middle::{
+    hir::map::Map,
+    ty::{TyCtxt, TypeckResults},
+};
+use std::mem::swap;
+
+/// Traverses the body to find the control flow graph and locations for the
+/// relevant places are dropped or reinitialized.
+///
+/// The resulting structure still needs to be iterated to a fixed point, which
+/// can be done with propagate_to_fixpoint in cfg_propagate.
+pub(super) fn build_control_flow_graph<'tcx>(
+    hir: Map<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    typeck_results: &TypeckResults<'tcx>,
+    consumed_borrowed_places: ConsumedAndBorrowedPlaces,
+    body: &'tcx Body<'tcx>,
+    num_exprs: usize,
+) -> DropRangesBuilder {
+    let mut drop_range_visitor =
+        DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
+    intravisit::walk_body(&mut drop_range_visitor, body);
+
+    drop_range_visitor.drop_ranges.process_deferred_edges();
+
+    drop_range_visitor.drop_ranges
+}
+
+/// This struct is used to gather the information for `DropRanges` to determine the regions of the
+/// HIR tree for which a value is dropped.
+///
+/// We are interested in points where a variables is dropped or initialized, and the control flow
+/// of the code. We identify locations in code by their post-order traversal index, so it is
+/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
+///
+/// We make several simplifying assumptions, with the goal of being more conservative than
+/// necessary rather than less conservative (since being less conservative is unsound, but more
+/// conservative is still safe). These assumptions are:
+///
+/// 1. Moving a variable `a` counts as a move of the whole variable.
+/// 2. Moving a partial path like `a.b.c` is ignored.
+/// 3. Reinitializing through a field (e.g. `a.b.c = 5`) counds as a reinitialization of all of
+///    `a`.
+///
+/// Some examples:
+///
+/// Rule 1:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a);
+/// // `a` is not considered initialized.
+/// ```
+///
+/// Rule 2:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a.0);
+/// drop(a.1);
+/// // `a` is still considered initialized.
+/// ```
+///
+/// Rule 3:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a);
+/// a.1 = vec![1];
+/// // all of `a` is considered initialized
+/// ```
+
+struct DropRangeVisitor<'a, 'tcx> {
+    hir: Map<'tcx>,
+    places: ConsumedAndBorrowedPlaces,
+    drop_ranges: DropRangesBuilder,
+    expr_index: PostOrderId,
+    tcx: TyCtxt<'tcx>,
+    typeck_results: &'a TypeckResults<'tcx>,
+}
+
+impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
+    fn new(
+        hir: Map<'tcx>,
+        tcx: TyCtxt<'tcx>,
+        typeck_results: &'a TypeckResults<'tcx>,
+        places: ConsumedAndBorrowedPlaces,
+        num_exprs: usize,
+    ) -> Self {
+        debug!("consumed_places: {:?}", places.consumed);
+        let drop_ranges = DropRangesBuilder::new(
+            places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
+            hir,
+            num_exprs,
+        );
+        Self { hir, places, drop_ranges, expr_index: PostOrderId::from_u32(0), typeck_results, tcx }
+    }
+
+    fn record_drop(&mut self, value: TrackedValue) {
+        if self.places.borrowed.contains(&value) {
+            debug!("not marking {:?} as dropped because it is borrowed at some point", value);
+        } else {
+            debug!("marking {:?} as dropped at {:?}", value, self.expr_index);
+            let count = self.expr_index;
+            self.drop_ranges.drop_at(value, count);
+        }
+    }
+
+    /// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
+    /// expressions. This method consumes a little deeper into the expression when needed.
+    fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
+        debug!("consuming expr {:?}, count={:?}", expr.hir_id, self.expr_index);
+        let places = self
+            .places
+            .consumed
+            .get(&expr.hir_id)
+            .map_or(vec![], |places| places.iter().cloned().collect());
+        for place in places {
+            for_each_consumable(self.hir, place, |value| self.record_drop(value));
+        }
+    }
+
+    /// Marks an expression as being reinitialized.
+    ///
+    /// Note that we always approximated on the side of things being more
+    /// initialized than they actually are, as opposed to less. In cases such
+    /// as `x.y = ...`, we would consider all of `x` as being initialized
+    /// instead of just the `y` field.
+    ///
+    /// This is because it is always safe to consider something initialized
+    /// even when it is not, but the other way around will cause problems.
+    ///
+    /// In the future, we will hopefully tighten up these rules to be more
+    /// precise.
+    fn reinit_expr(&mut self, expr: &hir::Expr<'_>) {
+        // Walk the expression to find the base. For example, in an expression
+        // like `*a[i].x`, we want to find the `a` and mark that as
+        // reinitialized.
+        match expr.kind {
+            ExprKind::Path(hir::QPath::Resolved(
+                _,
+                hir::Path { res: hir::def::Res::Local(hir_id), .. },
+            )) => {
+                // This is the base case, where we have found an actual named variable.
+
+                let location = self.expr_index;
+                debug!("reinitializing {:?} at {:?}", hir_id, location);
+                self.drop_ranges.reinit_at(TrackedValue::Variable(*hir_id), location);
+            }
+
+            ExprKind::Field(base, _) => self.reinit_expr(base),
+
+            // Most expressions do not refer to something where we need to track
+            // reinitializations.
+            //
+            // Some of these may be interesting in the future
+            ExprKind::Path(..)
+            | ExprKind::Box(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Array(..)
+            | ExprKind::Call(..)
+            | ExprKind::MethodCall(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Binary(..)
+            | ExprKind::Unary(..)
+            | ExprKind::Lit(..)
+            | ExprKind::Cast(..)
+            | ExprKind::Type(..)
+            | ExprKind::DropTemps(..)
+            | ExprKind::Let(..)
+            | ExprKind::If(..)
+            | ExprKind::Loop(..)
+            | ExprKind::Match(..)
+            | ExprKind::Closure(..)
+            | ExprKind::Block(..)
+            | ExprKind::Assign(..)
+            | ExprKind::AssignOp(..)
+            | ExprKind::Index(..)
+            | ExprKind::AddrOf(..)
+            | ExprKind::Break(..)
+            | ExprKind::Continue(..)
+            | ExprKind::Ret(..)
+            | ExprKind::InlineAsm(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Yield(..)
+            | ExprKind::Err => (),
+        }
+    }
+
+    /// For an expression with an uninhabited return type (e.g. a function that returns !),
+    /// this adds a self edge to to the CFG to model the fact that the function does not
+    /// return.
+    fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
+        let ty = self.typeck_results.expr_ty(expr);
+        let ty = self.tcx.erase_regions(ty);
+        let m = self.tcx.parent_module(expr.hir_id).to_def_id();
+        let param_env = self.tcx.param_env(m.expect_local());
+        if self.tcx.is_ty_uninhabited_from(m, ty, param_env) {
+            // This function will not return. We model this fact as an infinite loop.
+            self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let mut reinit = None;
+        match expr.kind {
+            ExprKind::Assign(lhs, rhs, _) => {
+                self.visit_expr(lhs);
+                self.visit_expr(rhs);
+
+                reinit = Some(lhs);
+            }
+
+            ExprKind::If(test, if_true, if_false) => {
+                self.visit_expr(test);
+
+                let fork = self.expr_index;
+
+                self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
+                self.visit_expr(if_true);
+                let true_end = self.expr_index;
+
+                self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
+                if let Some(if_false) = if_false {
+                    self.visit_expr(if_false);
+                }
+
+                self.drop_ranges.add_control_edge(true_end, self.expr_index + 1);
+            }
+            ExprKind::Match(scrutinee, arms, ..) => {
+                // We walk through the match expression almost like a chain of if expressions.
+                // Here's a diagram to follow along with:
+                //
+                //           ┌─┐
+                //     match │A│ {
+                //       ┌───┴─┘
+                //       │
+                //      ┌▼┌───►┌─┐   ┌─┐
+                //      │B│ if │C│ =>│D│,
+                //      └─┘    ├─┴──►└─┴──────┐
+                //          ┌──┘              │
+                //       ┌──┘                 │
+                //       │                    │
+                //      ┌▼┌───►┌─┐   ┌─┐      │
+                //      │E│ if │F│ =>│G│,     │
+                //      └─┘    ├─┴──►└─┴┐     │
+                //             │        │     │
+                //     }       ▼        ▼     │
+                //     ┌─┐◄───────────────────┘
+                //     │H│
+                //     └─┘
+                //
+                // The order we want is that the scrutinee (A) flows into the first pattern (B),
+                // which flows into the guard (C). Then the guard either flows into the arm body
+                // (D) or into the start of the next arm (E). Finally, the body flows to the end
+                // of the match block (H).
+                //
+                // The subsequent arms follow the same ordering. First we go to the pattern, then
+                // the guard (if present, otherwise it flows straight into the body), then into
+                // the body and then to the end of the match expression.
+                //
+                // The comments below show which edge is being added.
+                self.visit_expr(scrutinee);
+
+                let (guard_exit, arm_end_ids) = arms.iter().fold(
+                    (self.expr_index, vec![]),
+                    |(incoming_edge, mut arm_end_ids), hir::Arm { pat, body, guard, .. }| {
+                        // A -> B, or C -> E
+                        self.drop_ranges.add_control_edge(incoming_edge, self.expr_index + 1);
+                        self.visit_pat(pat);
+                        // B -> C and E -> F are added implicitly due to the traversal order.
+                        match guard {
+                            Some(Guard::If(expr)) => self.visit_expr(expr),
+                            Some(Guard::IfLet(pat, expr)) => {
+                                self.visit_pat(pat);
+                                self.visit_expr(expr);
+                            }
+                            None => (),
+                        }
+                        // Likewise, C -> D and F -> G are added implicitly.
+
+                        // Save C, F, so we can add the other outgoing edge.
+                        let to_next_arm = self.expr_index;
+
+                        // The default edge does not get added since we also have an explicit edge,
+                        // so we also need to add an edge to the next node as well.
+                        //
+                        // This adds C -> D, F -> G
+                        self.drop_ranges.add_control_edge(self.expr_index, self.expr_index + 1);
+                        self.visit_expr(body);
+
+                        // Save the end of the body so we can add the exit edge once we know where
+                        // the exit is.
+                        arm_end_ids.push(self.expr_index);
+
+                        // Pass C to the next iteration, as well as vec![D]
+                        //
+                        // On the last round through, we pass F and vec![D, G] so that we can
+                        // add all the exit edges.
+                        (to_next_arm, arm_end_ids)
+                    },
+                );
+                // F -> H
+                self.drop_ranges.add_control_edge(guard_exit, self.expr_index + 1);
+
+                arm_end_ids.into_iter().for_each(|arm_end| {
+                    // D -> H, G -> H
+                    self.drop_ranges.add_control_edge(arm_end, self.expr_index + 1)
+                });
+            }
+
+            ExprKind::Loop(body, ..) => {
+                let loop_begin = self.expr_index + 1;
+                if body.stmts.is_empty() && body.expr.is_none() {
+                    // For empty loops we won't have updated self.expr_index after visiting the
+                    // body, meaning we'd get an edge from expr_index to expr_index + 1, but
+                    // instead we want an edge from expr_index + 1 to expr_index + 1.
+                    self.drop_ranges.add_control_edge(loop_begin, loop_begin);
+                } else {
+                    self.visit_block(body);
+                    self.drop_ranges.add_control_edge(self.expr_index, loop_begin);
+                }
+            }
+            ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..)
+            | ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => {
+                self.drop_ranges.add_control_edge_hir_id(self.expr_index, target);
+            }
+
+            ExprKind::Call(f, args) => {
+                self.visit_expr(f);
+                for arg in args {
+                    self.visit_expr(arg);
+                }
+
+                self.handle_uninhabited_return(expr);
+            }
+            ExprKind::MethodCall(_, _, exprs, _) => {
+                for expr in exprs {
+                    self.visit_expr(expr);
+                }
+
+                self.handle_uninhabited_return(expr);
+            }
+
+            ExprKind::AddrOf(..)
+            | ExprKind::Array(..)
+            | ExprKind::AssignOp(..)
+            | ExprKind::Binary(..)
+            | ExprKind::Block(..)
+            | ExprKind::Box(..)
+            | ExprKind::Break(..)
+            | ExprKind::Cast(..)
+            | ExprKind::Closure(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Continue(..)
+            | ExprKind::DropTemps(..)
+            | ExprKind::Err
+            | ExprKind::Field(..)
+            | ExprKind::Index(..)
+            | ExprKind::InlineAsm(..)
+            | ExprKind::Let(..)
+            | ExprKind::Lit(..)
+            | ExprKind::Path(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Type(..)
+            | ExprKind::Unary(..)
+            | ExprKind::Yield(..) => intravisit::walk_expr(self, expr),
+        }
+
+        self.expr_index = self.expr_index + 1;
+        self.drop_ranges.add_node_mapping(expr.hir_id, self.expr_index);
+        self.consume_expr(expr);
+        if let Some(expr) = reinit {
+            self.reinit_expr(expr);
+        }
+    }
+
+    fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
+        intravisit::walk_pat(self, pat);
+
+        // Increment expr_count here to match what InteriorVisitor expects.
+        self.expr_index = self.expr_index + 1;
+    }
+}
+
+impl DropRangesBuilder {
+    fn new(
+        tracked_values: impl Iterator<Item = TrackedValue>,
+        hir: Map<'_>,
+        num_exprs: usize,
+    ) -> Self {
+        let mut tracked_value_map = FxHashMap::<_, TrackedValueIndex>::default();
+        let mut next = <_>::from(0u32);
+        for value in tracked_values {
+            for_each_consumable(hir, value, |value| {
+                if !tracked_value_map.contains_key(&value) {
+                    tracked_value_map.insert(value, next);
+                    next = next + 1;
+                }
+            });
+        }
+        debug!("hir_id_map: {:?}", tracked_value_map);
+        let num_values = tracked_value_map.len();
+        Self {
+            tracked_value_map,
+            nodes: IndexVec::from_fn_n(|_| NodeInfo::new(num_values), num_exprs + 1),
+            deferred_edges: <_>::default(),
+            post_order_map: <_>::default(),
+        }
+    }
+
+    fn tracked_value_index(&self, tracked_value: TrackedValue) -> TrackedValueIndex {
+        *self.tracked_value_map.get(&tracked_value).unwrap()
+    }
+
+    /// Adds an entry in the mapping from HirIds to PostOrderIds
+    ///
+    /// Needed so that `add_control_edge_hir_id` can work.
+    fn add_node_mapping(&mut self, node_hir_id: HirId, post_order_id: PostOrderId) {
+        self.post_order_map.insert(node_hir_id, post_order_id);
+    }
+
+    /// Like add_control_edge, but uses a hir_id as the target.
+    ///
+    /// This can be used for branches where we do not know the PostOrderId of the target yet,
+    /// such as when handling `break` or `continue`.
+    fn add_control_edge_hir_id(&mut self, from: PostOrderId, to: HirId) {
+        self.deferred_edges.push((from, to));
+    }
+
+    fn drop_at(&mut self, value: TrackedValue, location: PostOrderId) {
+        let value = self.tracked_value_index(value);
+        self.node_mut(location.into()).drops.push(value);
+    }
+
+    fn reinit_at(&mut self, value: TrackedValue, location: PostOrderId) {
+        let value = match self.tracked_value_map.get(&value) {
+            Some(value) => *value,
+            // If there's no value, this is never consumed and therefore is never dropped. We can
+            // ignore this.
+            None => return,
+        };
+        self.node_mut(location.into()).reinits.push(value);
+    }
+
+    /// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.
+    ///
+    /// Should be called after visiting the HIR but before solving the control flow, otherwise some
+    /// edges will be missed.
+    fn process_deferred_edges(&mut self) {
+        let mut edges = vec![];
+        swap(&mut edges, &mut self.deferred_edges);
+        edges.into_iter().for_each(|(from, to)| {
+            let to = *self.post_order_map.get(&to).expect("Expression ID not found");
+            trace!("Adding deferred edge from {:?} to {:?}", from, to);
+            self.add_control_edge(from, to)
+        });
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
new file mode 100644
index 00000000000..139d17d2e1c
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
@@ -0,0 +1,92 @@
+use super::{DropRangesBuilder, PostOrderId};
+use rustc_index::{bit_set::BitSet, vec::IndexVec};
+use std::collections::BTreeMap;
+
+impl DropRangesBuilder {
+    pub fn propagate_to_fixpoint(&mut self) {
+        trace!("before fixpoint: {:#?}", self);
+        let preds = self.compute_predecessors();
+
+        trace!("predecessors: {:#?}", preds.iter_enumerated().collect::<BTreeMap<_, _>>());
+
+        let mut new_state = BitSet::new_empty(self.num_values());
+        let mut changed_nodes = BitSet::new_empty(self.nodes.len());
+        let mut unchanged_mask = BitSet::new_filled(self.nodes.len());
+        changed_nodes.insert(0u32.into());
+
+        let mut propagate = || {
+            let mut changed = false;
+            unchanged_mask.insert_all();
+            for id in self.nodes.indices() {
+                trace!("processing {:?}, changed_nodes: {:?}", id, changed_nodes);
+                // Check if any predecessor has changed, and if not then short-circuit.
+                //
+                // We handle the start node specially, since it doesn't have any predecessors,
+                // but we need to start somewhere.
+                if match id.index() {
+                    0 => !changed_nodes.contains(id),
+                    _ => !preds[id].iter().any(|pred| changed_nodes.contains(*pred)),
+                } {
+                    trace!("short-circuiting because none of {:?} have changed", preds[id]);
+                    unchanged_mask.remove(id);
+                    continue;
+                }
+
+                if id.index() == 0 {
+                    new_state.clear();
+                } else {
+                    // If we are not the start node and we have no predecessors, treat
+                    // everything as dropped because there's no way to get here anyway.
+                    new_state.insert_all();
+                };
+
+                for pred in &preds[id] {
+                    new_state.intersect(&self.nodes[*pred].drop_state);
+                }
+
+                for drop in &self.nodes[id].drops {
+                    new_state.insert(*drop);
+                }
+
+                for reinit in &self.nodes[id].reinits {
+                    new_state.remove(*reinit);
+                }
+
+                if self.nodes[id].drop_state.intersect(&new_state) {
+                    changed_nodes.insert(id);
+                    changed = true;
+                } else {
+                    unchanged_mask.remove(id);
+                }
+            }
+
+            changed_nodes.intersect(&unchanged_mask);
+            changed
+        };
+
+        while propagate() {
+            trace!("drop_state changed, re-running propagation");
+        }
+
+        trace!("after fixpoint: {:#?}", self);
+    }
+
+    fn compute_predecessors(&self) -> IndexVec<PostOrderId, Vec<PostOrderId>> {
+        let mut preds = IndexVec::from_fn_n(|_| vec![], self.nodes.len());
+        for (id, node) in self.nodes.iter_enumerated() {
+            // If the node has no explicit successors, we assume that control
+            // will from this node into the next one.
+            //
+            // If there are successors listed, then we assume that all
+            // possible successors are given and we do not include the default.
+            if node.successors.len() == 0 && id.index() != self.nodes.len() - 1 {
+                preds[id + 1].push(id);
+            } else {
+                for succ in &node.successors {
+                    preds[*succ].push(id);
+                }
+            }
+        }
+        preds
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
new file mode 100644
index 00000000000..20aad7aedf7
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
@@ -0,0 +1,77 @@
+//! Implementation of GraphWalk for DropRanges so we can visualize the control
+//! flow graph when needed for debugging.
+
+use rustc_graphviz as dot;
+
+use super::{DropRangesBuilder, PostOrderId};
+
+/// Writes the CFG for DropRangesBuilder to a .dot file for visualization.
+///
+/// It is not normally called, but is kept around to easily add debugging
+/// code when needed.
+#[allow(dead_code)]
+pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) {
+    dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap();
+}
+
+impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
+    type Node = PostOrderId;
+
+    type Edge = (PostOrderId, PostOrderId);
+
+    fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
+        self.nodes.iter_enumerated().map(|(i, _)| i).collect()
+    }
+
+    fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
+        self.nodes
+            .iter_enumerated()
+            .flat_map(|(i, node)| {
+                if node.successors.len() == 0 {
+                    vec![(i, i + 1)]
+                } else {
+                    node.successors.iter().map(move |&s| (i, s)).collect()
+                }
+            })
+            .collect()
+    }
+
+    fn source(&'a self, edge: &Self::Edge) -> Self::Node {
+        edge.0
+    }
+
+    fn target(&'a self, edge: &Self::Edge) -> Self::Node {
+        edge.1
+    }
+}
+
+impl<'a> dot::Labeller<'a> for DropRangesBuilder {
+    type Node = PostOrderId;
+
+    type Edge = (PostOrderId, PostOrderId);
+
+    fn graph_id(&'a self) -> dot::Id<'a> {
+        dot::Id::new("drop_ranges").unwrap()
+    }
+
+    fn node_id(&'a self, n: &Self::Node) -> dot::Id<'a> {
+        dot::Id::new(format!("id{}", n.index())).unwrap()
+    }
+
+    fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
+        dot::LabelText::LabelStr(
+            format!(
+                "{:?}, local_id: {}",
+                n,
+                self.post_order_map
+                    .iter()
+                    .find(|(_hir_id, &post_order_id)| post_order_id == *n)
+                    .map_or("<unknown>".into(), |(hir_id, _)| format!(
+                        "{}",
+                        hir_id.local_id.index()
+                    ))
+            )
+            .into(),
+        )
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
new file mode 100644
index 00000000000..059a135a6fb
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -0,0 +1,118 @@
+use super::TrackedValue;
+use crate::{
+    check::FnCtxt,
+    expr_use_visitor::{self, ExprUseVisitor},
+};
+use hir::{def_id::DefId, Body, HirId, HirIdMap};
+use rustc_data_structures::stable_set::FxHashSet;
+use rustc_hir as hir;
+use rustc_middle::hir::map::Map;
+
+pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    def_id: DefId,
+    body: &'tcx Body<'tcx>,
+) -> ConsumedAndBorrowedPlaces {
+    let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx.hir());
+    expr_use_visitor.consume_body(fcx, def_id, body);
+    expr_use_visitor.places
+}
+
+pub(super) struct ConsumedAndBorrowedPlaces {
+    /// Records the variables/expressions that are dropped by a given expression.
+    ///
+    /// The key is the hir-id of the expression, and the value is a set or hir-ids for variables
+    /// or values that are consumed by that expression.
+    ///
+    /// Note that this set excludes "partial drops" -- for example, a statement like `drop(x.y)` is
+    /// not considered a drop of `x`, although it would be a drop of `x.y`.
+    pub(super) consumed: HirIdMap<FxHashSet<TrackedValue>>,
+    /// A set of hir-ids of values or variables that are borrowed at some point within the body.
+    pub(super) borrowed: FxHashSet<TrackedValue>,
+}
+
+/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
+///
+/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
+/// record the parent expression, which is the point where the drop actually takes place.
+struct ExprUseDelegate<'tcx> {
+    hir: Map<'tcx>,
+    places: ConsumedAndBorrowedPlaces,
+}
+
+impl<'tcx> ExprUseDelegate<'tcx> {
+    fn new(hir: Map<'tcx>) -> Self {
+        Self {
+            hir,
+            places: ConsumedAndBorrowedPlaces {
+                consumed: <_>::default(),
+                borrowed: <_>::default(),
+            },
+        }
+    }
+
+    fn consume_body(&mut self, fcx: &'_ FnCtxt<'_, 'tcx>, def_id: DefId, body: &'tcx Body<'tcx>) {
+        // Run ExprUseVisitor to find where values are consumed.
+        ExprUseVisitor::new(
+            self,
+            &fcx.infcx,
+            def_id.expect_local(),
+            fcx.param_env,
+            &fcx.typeck_results.borrow(),
+        )
+        .consume_body(body);
+    }
+
+    fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) {
+        if !self.places.consumed.contains_key(&consumer) {
+            self.places.consumed.insert(consumer, <_>::default());
+        }
+        self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
+    }
+}
+
+impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
+    fn consume(
+        &mut self,
+        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        diag_expr_id: HirId,
+    ) {
+        let parent = match self.hir.find_parent_node(place_with_id.hir_id) {
+            Some(parent) => parent,
+            None => place_with_id.hir_id,
+        };
+        debug!(
+            "consume {:?}; diag_expr_id={:?}, using parent {:?}",
+            place_with_id, diag_expr_id, parent
+        );
+        place_with_id
+            .try_into()
+            .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
+    }
+
+    fn borrow(
+        &mut self,
+        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        _diag_expr_id: HirId,
+        _bk: rustc_middle::ty::BorrowKind,
+    ) {
+        place_with_id
+            .try_into()
+            .map_or(false, |tracked_value| self.places.borrowed.insert(tracked_value));
+    }
+
+    fn mutate(
+        &mut self,
+        _assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        _diag_expr_id: HirId,
+    ) {
+    }
+
+    fn fake_read(
+        &mut self,
+        _place: expr_use_visitor::Place<'tcx>,
+        _cause: rustc_middle::mir::FakeReadCause,
+        _diag_expr_id: HirId,
+    ) {
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 6314f2aba4e..4c612ed5be5 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -453,7 +453,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()),
         sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
         sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)),
-        sym::simd_cast => (2, vec![param(0)], param(1)),
+        sym::simd_cast | sym::simd_as => (2, vec![param(0)], param(1)),
         sym::simd_bitmask => (2, vec![param(0)], param(1)),
         sym::simd_select | sym::simd_select_bitmask => {
             (2, vec![param(0), param(1), param(1)], param(1))
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index dabfe92190b..27c39934ba8 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -149,7 +149,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // time writing the results into the various typeck results.
         let mut autoderef =
             self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
-        let (_, n) = match autoderef.nth(pick.autoderefs) {
+        let (ty, n) = match autoderef.nth(pick.autoderefs) {
             Some(n) => n,
             None => {
                 return self.tcx.ty_error_with_message(
@@ -161,14 +161,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         assert_eq!(n, pick.autoderefs);
 
         let mut adjustments = self.adjust_steps(&autoderef);
+        let mut target = self.structurally_resolved_type(autoderef.span(), ty);
 
-        let mut target =
-            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
-
-        match &pick.autoref_or_ptr_adjustment {
+        match pick.autoref_or_ptr_adjustment {
             Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
                 let region = self.next_region_var(infer::Autoref(self.span));
-                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
+                // Type we're wrapping in a reference, used later for unsizing
+                let base_ty = target;
+
+                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
                 let mutbl = match mutbl {
                     hir::Mutability::Not => AutoBorrowMutability::Not,
                     hir::Mutability::Mut => AutoBorrowMutability::Mut {
@@ -182,10 +183,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     target,
                 });
 
-                if let Some(unsize_target) = unsize {
+                if unsize {
+                    let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
+                        self.tcx.mk_slice(elem_ty)
+                    } else {
+                        bug!(
+                            "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
+                            base_ty
+                        )
+                    };
                     target = self
                         .tcx
-                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsize_target });
+                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
                     adjustments
                         .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
                 }
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index b704ff8c7cb..86f3568d2e3 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -167,26 +167,26 @@ enum ProbeResult {
 /// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
 /// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
 /// `mut`), or it has type `*mut T` and we convert it to `*const T`.
-#[derive(Debug, PartialEq, Clone)]
-pub enum AutorefOrPtrAdjustment<'tcx> {
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum AutorefOrPtrAdjustment {
     /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
     /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
     Autoref {
         mutbl: hir::Mutability,
 
-        /// Indicates that the source expression should be "unsized" to a target type. This should
-        /// probably eventually go away in favor of just coercing method receivers.
-        unsize: Option<Ty<'tcx>>,
+        /// Indicates that the source expression should be "unsized" to a target type.
+        /// This is special-cased for just arrays unsizing to slices.
+        unsize: bool,
     },
     /// Receiver has type `*mut T`, convert to `*const T`
     ToConstPtr,
 }
 
-impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
-    fn get_unsize(&self) -> Option<Ty<'tcx>> {
+impl AutorefOrPtrAdjustment {
+    fn get_unsize(&self) -> bool {
         match self {
             AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
-            AutorefOrPtrAdjustment::ToConstPtr => None,
+            AutorefOrPtrAdjustment::ToConstPtr => false,
         }
     }
 }
@@ -204,7 +204,7 @@ pub struct Pick<'tcx> {
 
     /// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
     /// `*mut T`, convert it to `*const T`.
-    pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment<'tcx>>,
+    pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
     pub self_ty: Ty<'tcx>,
 }
 
@@ -1202,7 +1202,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     pick.autoderefs += 1;
                     pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
                         mutbl,
-                        unsize: pick.autoref_or_ptr_adjustment.and_then(|a| a.get_unsize()),
+                        unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
                     })
                 }
 
@@ -1227,10 +1227,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         self.pick_method(autoref_ty, unstable_candidates).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
-                pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
-                    mutbl,
-                    unsize: step.unsize.then_some(self_ty),
-                });
+                pick.autoref_or_ptr_adjustment =
+                    Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize });
                 pick
             })
         })
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index f2fe4403d55..96ab800afaf 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -789,10 +789,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     item_def_id: projection_ty.item_def_id,
                                 };
 
-                                let ty = pred.skip_binder().ty;
+                                let term = pred.skip_binder().term;
 
-                                let obligation = format!("{} = {}", projection_ty, ty);
-                                let quiet = format!("{} = {}", quiet_projection_ty, ty);
+                                let obligation = format!("{} = {}", projection_ty, term);
+                                let quiet = format!("{} = {}", quiet_projection_ty, term);
 
                                 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
                                 Some((obligation, projection_ty.self_ty()))
@@ -1274,7 +1274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
     ) {
         let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
-            Some(output_ty) => self.resolve_vars_if_possible(output_ty),
+            Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(),
             _ => return,
         };
         let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 719266ad5a4..34caabe44d6 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -637,6 +637,31 @@ fn missing_items_err(
     err.emit();
 }
 
+fn missing_items_must_implement_one_of_err(
+    tcx: TyCtxt<'_>,
+    impl_span: Span,
+    missing_items: &[Ident],
+    annotation_span: Option<Span>,
+) {
+    let missing_items_msg =
+        missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
+
+    let mut err = struct_span_err!(
+        tcx.sess,
+        impl_span,
+        E0046,
+        "not all trait items implemented, missing one of: `{}`",
+        missing_items_msg
+    );
+    err.span_label(impl_span, format!("missing one of `{}` in implementation", missing_items_msg));
+
+    if let Some(annotation_span) = annotation_span {
+        err.span_note(annotation_span, "required because of this annotation");
+    }
+
+    err.emit();
+}
+
 /// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
 fn bounds_from_generic_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -691,7 +716,11 @@ fn bounds_from_generic_predicates<'tcx>(
         // insert the associated types where they correspond, but for now let's be "lazy" and
         // propose this instead of the following valid resugaring:
         // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
-        where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty));
+        where_clauses.push(format!(
+            "{} = {}",
+            tcx.def_path_str(p.projection_ty.item_def_id),
+            p.term,
+        ));
     }
     let where_clauses = if where_clauses.is_empty() {
         String::new()
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index f50f3c39c88..ec88bdf4a37 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let item_def_id = self.tcx.hir().local_def_id(item_id);
 
         // This attribute causes us to dump some writeback information
-        // in the form of errors, which is uSymbol for unit tests.
+        // in the form of errors, which is used for unit tests.
         let rustc_dump_user_substs =
             self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_dump_user_substs);
 
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 2ed98e20f1d..cf519a9ab32 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -112,9 +112,9 @@ pub struct ItemCtxt<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 
 #[derive(Default)]
-crate struct PlaceholderHirTyCollector(crate Vec<Span>);
+crate struct HirPlaceholderCollector(crate Vec<Span>);
 
-impl<'v> Visitor<'v> for PlaceholderHirTyCollector {
+impl<'v> Visitor<'v> for HirPlaceholderCollector {
     fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
         if let hir::TyKind::Infer = t.kind {
             self.0.push(t.span);
@@ -131,6 +131,12 @@ impl<'v> Visitor<'v> for PlaceholderHirTyCollector {
             _ => {}
         }
     }
+    fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
+        if let &hir::ArrayLen::Infer(_, span) = length {
+            self.0.push(span);
+        }
+        intravisit::walk_array_len(self, length)
+    }
 }
 
 struct CollectItemTypesVisitor<'tcx> {
@@ -175,7 +181,7 @@ crate fn placeholder_type_error<'tcx>(
         sugg.push((span, format!(", {}", type_name)));
     }
 
-    let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
+    let mut err = bad_placeholder(tcx, placeholder_types, kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -233,7 +239,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
         _ => return,
     };
 
-    let mut visitor = PlaceholderHirTyCollector::default();
+    let mut visitor = HirPlaceholderCollector::default();
     visitor.visit_item(item);
 
     placeholder_type_error(
@@ -311,7 +317,6 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
 
 fn bad_placeholder<'tcx>(
     tcx: TyCtxt<'tcx>,
-    placeholder_kind: &'static str,
     mut spans: Vec<Span>,
     kind: &'static str,
 ) -> rustc_errors::DiagnosticBuilder<'tcx> {
@@ -322,8 +327,7 @@ fn bad_placeholder<'tcx>(
         tcx.sess,
         spans.clone(),
         E0121,
-        "the {} placeholder `_` is not allowed within types on item signatures for {}",
-        placeholder_kind,
+        "the placeholder `_` is not allowed within types on item signatures for {}",
         kind
     );
     for span in spans {
@@ -381,7 +385,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
     }
 
     fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
-        self.tcx().ty_error_with_message(span, "bad_placeholder_type")
+        self.tcx().ty_error_with_message(span, "bad placeholder type")
     }
 
     fn ct_infer(
@@ -390,13 +394,11 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         _: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> &'tcx Const<'tcx> {
-        bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
-        // Typeck doesn't expect erased regions to be returned from `type_of`.
         let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
             ty::ReErased => self.tcx.lifetimes.re_static,
             _ => r,
         });
-        self.tcx().const_error(ty)
+        self.tcx().const_error_with_message(ty, span, "bad placeholder constant")
     }
 
     fn projected_ty_from_poly_trait_ref(
@@ -659,7 +661,11 @@ impl<'tcx> ItemCtxt<'tcx> {
             .params
             .iter()
             .filter_map(|param| match param.kind {
-                GenericParamKind::Type { .. } if param.hir_id == param_id => Some(&param.bounds),
+                GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
+                    if param.hir_id == param_id =>
+                {
+                    Some(&param.bounds)
+                }
                 _ => None,
             })
             .flat_map(|bounds| bounds.iter())
@@ -739,7 +745,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 match item.kind {
                     hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
                     hir::ForeignItemKind::Static(..) => {
-                        let mut visitor = PlaceholderHirTyCollector::default();
+                        let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_foreign_item(item);
                         placeholder_type_error(
                             tcx,
@@ -822,7 +828,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 hir::ItemKind::Const(ty, ..) | hir::ItemKind::Static(ty, ..) => {
                     // (#75889): Account for `const C: dyn Fn() -> _ = "";`
                     if let hir::TyKind::TraitObject(..) = ty.kind {
-                        let mut visitor = PlaceholderHirTyCollector::default();
+                        let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_item(it);
                         placeholder_type_error(
                             tcx,
@@ -858,7 +864,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         hir::TraitItemKind::Const(..) => {
             tcx.ensure().type_of(trait_item_id.def_id);
             // Account for `const C: _;`.
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "constant");
         }
@@ -867,7 +873,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             tcx.ensure().item_bounds(trait_item_id.def_id);
             tcx.ensure().type_of(trait_item_id.def_id);
             // Account for `type T = _;`.
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
         }
@@ -876,7 +882,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             tcx.ensure().item_bounds(trait_item_id.def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
 
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
@@ -898,7 +904,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
         }
         hir::ImplItemKind::TyAlias(_) => {
             // Account for `type T = _;`
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_impl_item(impl_item);
 
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
@@ -1190,9 +1196,11 @@ fn super_predicates_that_define_assoc_type(
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
     let item = tcx.hir().expect_item(def_id.expect_local());
 
-    let (is_auto, unsafety) = match item.kind {
-        hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety),
-        hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal),
+    let (is_auto, unsafety, items) = match item.kind {
+        hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
+            (is_auto == hir::IsAuto::Yes, unsafety, items)
+        }
+        hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal, &[][..]),
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
@@ -1219,6 +1227,103 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
         ty::trait_def::TraitSpecializationKind::None
     };
     let def_path_hash = tcx.def_path_hash(def_id);
+
+    let must_implement_one_of = tcx
+        .get_attrs(def_id)
+        .iter()
+        .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+        // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
+        // and that they are all identifiers
+        .and_then(|attr| match attr.meta_item_list() {
+            Some(items) if items.len() < 2 => {
+                tcx.sess
+                    .struct_span_err(
+                        attr.span,
+                        "the `#[rustc_must_implement_one_of]` attribute must be \
+                        used with at least 2 args",
+                    )
+                    .emit();
+
+                None
+            }
+            Some(items) => items
+                .into_iter()
+                .map(|item| item.ident().ok_or(item.span()))
+                .collect::<Result<Box<[_]>, _>>()
+                .map_err(|span| {
+                    tcx.sess
+                        .struct_span_err(span, "must be a name of an associated function")
+                        .emit();
+                })
+                .ok()
+                .zip(Some(attr.span)),
+            // Error is reported by `rustc_attr!`
+            None => None,
+        })
+        // Check that all arguments of `#[rustc_must_implement_one_of]` reference
+        // functions in the trait with default implementations
+        .and_then(|(list, attr_span)| {
+            let errors = list.iter().filter_map(|ident| {
+                let item = items.iter().find(|item| item.ident == *ident);
+
+                match item {
+                    Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
+                        if !item.defaultness.has_value() {
+                            tcx.sess
+                                .struct_span_err(
+                                    item.span,
+                                    "This function doesn't have a default implementation",
+                                )
+                                .span_note(attr_span, "required by this annotation")
+                                .emit();
+
+                            return Some(());
+                        }
+
+                        return None;
+                    }
+                    Some(item) => tcx
+                        .sess
+                        .struct_span_err(item.span, "Not a function")
+                        .span_note(attr_span, "required by this annotation")
+                        .note(
+                            "All `#[rustc_must_implement_one_of]` arguments \
+                            must be associated function names",
+                        )
+                        .emit(),
+                    None => tcx
+                        .sess
+                        .struct_span_err(ident.span, "Function not found in this trait")
+                        .emit(),
+                }
+
+                Some(())
+            });
+
+            (errors.count() == 0).then_some(list)
+        })
+        // Check for duplicates
+        .and_then(|list| {
+            let mut set: FxHashMap<Symbol, Span> = FxHashMap::default();
+            let mut no_dups = true;
+
+            for ident in &*list {
+                if let Some(dup) = set.insert(ident.name, ident.span) {
+                    tcx.sess
+                        .struct_span_err(vec![dup, ident.span], "Functions names are duplicated")
+                        .note(
+                            "All `#[rustc_must_implement_one_of]` arguments \
+                            must be unique",
+                        )
+                        .emit();
+
+                    no_dups = false;
+                }
+            }
+
+            no_dups.then_some(list)
+        });
+
     ty::TraitDef::new(
         def_id,
         unsafety,
@@ -1228,6 +1333,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
         skip_array_during_method_dispatch,
         spec_kind,
         def_path_hash,
+        must_implement_one_of,
     )
 }
 
@@ -1718,10 +1824,14 @@ fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
 /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
 /// use inference to provide suggestions for the appropriate type if possible.
 fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
+    debug!(?ty);
     use hir::TyKind::*;
     match &ty.kind {
         Infer => true,
-        Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
+        Slice(ty) => is_suggestable_infer_ty(ty),
+        Array(ty, length) => {
+            is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
+        }
         Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
         Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
         OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
@@ -1773,9 +1883,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     });
                     let fn_sig = ty::Binder::dummy(fn_sig);
 
-                    let mut visitor = PlaceholderHirTyCollector::default();
+                    let mut visitor = HirPlaceholderCollector::default();
                     visitor.visit_ty(ty);
-                    let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
+                    let mut diag = bad_placeholder(tcx, visitor.0, "return type");
                     let ret_ty = fn_sig.skip_binder().output();
                     if !ret_ty.references_error() {
                         if !ret_ty.is_closure() {
@@ -2427,7 +2537,7 @@ fn predicates_from_bound<'tcx>(
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     let mut bounds = Bounds::default();
     astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
-    bounds.predicates(astconv.tcx(), param_ty)
+    bounds.predicates(astconv.tcx(), param_ty).collect()
 }
 
 fn compute_sig_of_foreign_fn_decl<'tcx>(
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 26cad8fb180..87a67c4a4e0 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -67,11 +67,7 @@ fn opaque_type_bounds<'tcx>(
         let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
         <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
-        let bounds = bounds.predicates(tcx, item_ty);
-
-        debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
-
-        tcx.arena.alloc_slice(&bounds)
+        tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
     })
 }
 
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index bc7507bcc50..63020b7f90f 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -20,9 +20,6 @@ use super::{bad_placeholder, is_suggestable_infer_ty};
 /// This should be called using the query `tcx.opt_const_param_of`.
 #[instrument(level = "debug", skip(tcx))]
 pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
-    // FIXME(generic_arg_infer): allow for returning DefIds of inference of
-    // GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag
-    // for const or type.
     use hir::*;
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
@@ -753,7 +750,7 @@ fn infer_placeholder_type<'a>(
             err.emit();
         }
         None => {
-            let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
+            let mut diag = bad_placeholder(tcx, vec![span], kind);
 
             if !ty.references_error() {
                 let mut mk_nameable = MakeNameable::new(tcx);
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 10952901323..a0c8fc822df 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -203,7 +203,7 @@ pub fn setup_constraining_predicates<'tcx>(
                 if !relies_only_on_inputs {
                     continue;
                 }
-                input_parameters.extend(parameters_for(&projection.ty, false));
+                input_parameters.extend(parameters_for(&projection.term, false));
             } else {
                 continue;
             }
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 6296f2ab32a..d87e670a8fb 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -199,7 +199,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
     for (predicate, _) in impl_generic_predicates.predicates.iter() {
         if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
             let projection_ty = proj.projection_ty;
-            let projected_ty = proj.ty;
+            let projected_ty = proj.term;
 
             let unbound_trait_ref = projection_ty.trait_ref(tcx);
             if Some(unbound_trait_ref) == impl_trait_ref {
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index b2b607a2ffc..7c504a0d89c 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -308,11 +308,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
 
                 for projection in data.projection_bounds() {
-                    self.add_constraints_from_ty(
-                        current,
-                        projection.skip_binder().ty,
-                        self.invariant,
-                    );
+                    match projection.skip_binder().term {
+                        ty::Term::Ty(ty) => {
+                            self.add_constraints_from_ty(current, ty, self.invariant);
+                        }
+                        ty::Term::Const(c) => {
+                            self.add_constraints_from_const(current, c, self.invariant)
+                        }
+                    }
                 }
             }
 
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 3806bc546ee..8fa0242ca9a 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -108,7 +108,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     //   to round up a request of less than 8 bytes to at least 8 bytes.
     // - 4 if elements are moderate-sized (<= 1 KiB).
     // - 1 otherwise, to avoid wasting too much space for very short Vecs.
-    const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
+    pub(crate) const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
         8
     } else if mem::size_of::<T>() <= 1024 {
         4
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 8853577371a..a5c4140e313 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -375,7 +375,10 @@ impl<T> [T] {
 
     /// Sorts the slice with a key extraction function.
     ///
-    /// During sorting, the key function is called only once per element.
+    /// During sorting, the key function is called at most once per element, by using
+    /// temporary storage to remember the results of key evaluation.
+    /// The order of calls to the key function is unspecified and may change in future versions
+    /// of the standard library.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* log(*n*))
     /// worst-case, where the key function is *O*(*m*).
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 16ba5c008cd..bd3262b51d4 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2051,8 +2051,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(vec_spare_capacity)]
-    ///
     /// // Allocate vector big enough for 10 elements.
     /// let mut v = Vec::with_capacity(10);
     ///
@@ -2069,7 +2067,7 @@ impl<T, A: Allocator> Vec<T, A> {
     ///
     /// assert_eq!(&v, &[0, 1, 2]);
     /// ```
-    #[unstable(feature = "vec_spare_capacity", issue = "75017")]
+    #[stable(feature = "vec_spare_capacity", since = "1.60.0")]
     #[inline]
     pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
         // Note:
diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs
index 948cf044197..f915ebb86e5 100644
--- a/library/alloc/src/vec/spec_from_iter_nested.rs
+++ b/library/alloc/src/vec/spec_from_iter_nested.rs
@@ -1,5 +1,8 @@
+use core::cmp;
 use core::iter::TrustedLen;
-use core::ptr::{self};
+use core::ptr;
+
+use crate::raw_vec::RawVec;
 
 use super::{SpecExtend, Vec};
 
@@ -24,8 +27,11 @@ where
             None => return Vec::new(),
             Some(element) => {
                 let (lower, _) = iterator.size_hint();
-                let mut vector = Vec::with_capacity(lower.saturating_add(1));
+                let initial_capacity =
+                    cmp::max(RawVec::<T>::MIN_NON_ZERO_CAP, lower.saturating_add(1));
+                let mut vector = Vec::with_capacity(initial_capacity);
                 unsafe {
+                    // SAFETY: We requested capacity at least 1
                     ptr::write(vector.as_mut_ptr(), element);
                     vector.set_len(1);
                 }
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 7b8eeb90b5a..dcf51e3142a 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -31,7 +31,6 @@
 #![feature(iter_advance_by)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
-#![feature(vec_spare_capacity)]
 #![feature(string_remove_matches)]
 #![feature(const_btree_new)]
 #![feature(const_default_impls)]
diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs
index 560dd25ecff..2877e66eca8 100644
--- a/library/core/src/future/pending.rs
+++ b/library/core/src/future/pending.rs
@@ -12,7 +12,7 @@ use crate::task::{Context, Poll};
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 pub struct Pending<T> {
-    _data: marker::PhantomData<T>,
+    _data: marker::PhantomData<fn() -> T>,
 }
 
 /// Creates a future which never resolves, representing a computation that never
@@ -44,9 +44,6 @@ impl<T> Future for Pending<T> {
 }
 
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
-impl<T> Unpin for Pending<T> {}
-
-#[stable(feature = "future_readiness_fns", since = "1.48.0")]
 impl<T> Debug for Pending<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Pending").finish()
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 3ff84cc9672..53de8b42c05 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -602,7 +602,7 @@ pub trait BuildHasher {
 /// [`HashSet`]: ../../std/collections/struct.HashSet.html
 /// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts
 #[stable(since = "1.7.0", feature = "build_hasher")]
-pub struct BuildHasherDefault<H>(marker::PhantomData<H>);
+pub struct BuildHasherDefault<H>(marker::PhantomData<fn() -> H>);
 
 #[stable(since = "1.9.0", feature = "core_impl_debug")]
 impl<H> fmt::Debug for BuildHasherDefault<H> {
diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs
index 7abe01d17c9..98734c527f2 100644
--- a/library/core/src/iter/sources/empty.rs
+++ b/library/core/src/iter/sources/empty.rs
@@ -22,17 +22,17 @@ pub const fn empty<T>() -> Empty<T> {
     Empty(marker::PhantomData)
 }
 
+// Newtype for use in `PhantomData` to avoid
+// > error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
+// in `const fn empty<T>()` above.
+struct FnReturning<T>(fn() -> T);
+
 /// An iterator that yields nothing.
 ///
 /// This `struct` is created by the [`empty()`] function. See its documentation for more.
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "iter_empty", since = "1.2.0")]
-pub struct Empty<T>(marker::PhantomData<T>);
-
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Send for Empty<T> {}
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Sync for Empty<T> {}
+pub struct Empty<T>(marker::PhantomData<FnReturning<T>>);
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
 impl<T> fmt::Debug for Empty<T> {
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index dd2f7306356..e38c0412a0a 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -1,8 +1,9 @@
 use crate::any::type_name;
 use crate::fmt;
 use crate::intrinsics;
-use crate::mem::ManuallyDrop;
+use crate::mem::{self, ManuallyDrop};
 use crate::ptr;
+use crate::slice;
 
 /// A wrapper type to construct uninitialized instances of `T`.
 ///
@@ -1038,7 +1039,7 @@ impl<T> MaybeUninit<T> {
     /// ```
     ///
     /// ```
-    /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)]
+    /// #![feature(maybe_uninit_write_slice)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut vec = Vec::with_capacity(32);
@@ -1098,7 +1099,7 @@ impl<T> MaybeUninit<T> {
     /// ```
     ///
     /// ```
-    /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)]
+    /// #![feature(maybe_uninit_write_slice)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut vec = Vec::with_capacity(32);
@@ -1160,4 +1161,126 @@ impl<T> MaybeUninit<T> {
         // SAFETY: Valid elements have just been written into `this` so it is initialized
         unsafe { MaybeUninit::slice_assume_init_mut(this) }
     }
+
+    /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let val = 0x12345678i32;
+    /// let uninit = MaybeUninit::new(val);
+    /// let uninit_bytes = uninit.as_bytes();
+    /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(uninit_bytes) };
+    /// assert_eq!(bytes, val.to_ne_bytes());
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn as_bytes(&self) -> &[MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts(self.as_ptr() as *const MaybeUninit<u8>, mem::size_of::<T>())
+        }
+    }
+
+    /// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized
+    /// bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let val = 0x12345678i32;
+    /// let mut uninit = MaybeUninit::new(val);
+    /// let uninit_bytes = uninit.as_bytes_mut();
+    /// if cfg!(target_endian = "little") {
+    ///     uninit_bytes[0].write(0xcd);
+    /// } else {
+    ///     uninit_bytes[3].write(0xcd);
+    /// }
+    /// let val2 = unsafe { uninit.assume_init() };
+    /// assert_eq!(val2, 0x123456cd);
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts_mut(
+                self.as_mut_ptr() as *mut MaybeUninit<u8>,
+                mem::size_of::<T>(),
+            )
+        }
+    }
+
+    /// Returns the contents of this slice of `MaybeUninit` as a slice of potentially uninitialized
+    /// bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)];
+    /// let uninit_bytes = MaybeUninit::slice_as_bytes(&uninit);
+    /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(&uninit_bytes) };
+    /// let val1 = u16::from_ne_bytes(bytes[0..2].try_into().unwrap());
+    /// let val2 = u16::from_ne_bytes(bytes[2..4].try_into().unwrap());
+    /// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]);
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn slice_as_bytes(this: &[MaybeUninit<T>]) -> &[MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts(
+                this.as_ptr() as *const MaybeUninit<u8>,
+                this.len() * mem::size_of::<T>(),
+            )
+        }
+    }
+
+    /// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of
+    /// potentially uninitialized bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
+    /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit);
+    /// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]);
+    /// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) };
+    /// if cfg!(target_endian = "little") {
+    ///     assert_eq!(vals, &[0x3412u16, 0x7856u16]);
+    /// } else {
+    ///     assert_eq!(vals, &[0x1234u16, 0x5678u16]);
+    /// }
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn slice_as_bytes_mut(this: &mut [MaybeUninit<T>]) -> &mut [MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts_mut(
+                this.as_mut_ptr() as *mut MaybeUninit<u8>,
+                this.len() * mem::size_of::<T>(),
+            )
+        }
+    }
 }
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index 98d8a8a1d74..de85fdd6ed2 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -19,18 +19,8 @@
 )]
 #![macro_use]
 
-use crate::intrinsics;
-
 /// Arithmetic operations required by bignums.
 pub trait FullOps: Sized {
-    /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
-    /// where `W` is the number of bits in `Self`.
-    fn full_add(self, other: Self, carry: bool) -> (bool /* carry */, Self);
-
-    /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
-    /// where `W` is the number of bits in `Self`.
-    fn full_mul(self, other: Self, carry: Self) -> (Self /* carry */, Self);
-
     /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
     /// where `W` is the number of bits in `Self`.
     fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);
@@ -45,22 +35,6 @@ macro_rules! impl_full_ops {
     ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
         $(
             impl FullOps for $ty {
-                fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) {
-                    // This cannot overflow; the output is between `0` and `2 * 2^nbits - 1`.
-                    // FIXME: will LLVM optimize this into ADC or similar?
-                    let (v, carry1) = intrinsics::add_with_overflow(self, other);
-                    let (v, carry2) = intrinsics::add_with_overflow(v, if carry {1} else {0});
-                    (carry1 || carry2, v)
-                }
-
-                fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) {
-                    // This cannot overflow;
-                    // the output is between `0` and `2^nbits * (2^nbits - 1)`.
-                    // FIXME: will LLVM optimize this into ADC or similar?
-                    let v = (self as $bigty) * (other as $bigty) + (carry as $bigty);
-                    ((v >> <$ty>::BITS) as $ty, v as $ty)
-                }
-
                 fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
                     // This cannot overflow;
                     // the output is between `0` and `2^nbits * (2^nbits - 1)`.
@@ -173,12 +147,11 @@ macro_rules! define_bignum {
             pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
                 use crate::cmp;
                 use crate::iter;
-                use crate::num::bignum::FullOps;
 
                 let mut sz = cmp::max(self.size, other.size);
                 let mut carry = false;
                 for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
-                    let (c, v) = (*a).full_add(*b, carry);
+                    let (v, c) = (*a).carrying_add(*b, carry);
                     *a = v;
                     carry = c;
                 }
@@ -191,13 +164,11 @@ macro_rules! define_bignum {
             }
 
             pub fn add_small(&mut self, other: $ty) -> &mut $name {
-                use crate::num::bignum::FullOps;
-
-                let (mut carry, v) = self.base[0].full_add(other, false);
+                let (v, mut carry) = self.base[0].carrying_add(other, false);
                 self.base[0] = v;
                 let mut i = 1;
                 while carry {
-                    let (c, v) = self.base[i].full_add(0, carry);
+                    let (v, c) = self.base[i].carrying_add(0, carry);
                     self.base[i] = v;
                     carry = c;
                     i += 1;
@@ -212,12 +183,11 @@ macro_rules! define_bignum {
             pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
                 use crate::cmp;
                 use crate::iter;
-                use crate::num::bignum::FullOps;
 
                 let sz = cmp::max(self.size, other.size);
                 let mut noborrow = true;
                 for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
-                    let (c, v) = (*a).full_add(!*b, noborrow);
+                    let (v, c) = (*a).carrying_add(!*b, noborrow);
                     *a = v;
                     noborrow = c;
                 }
@@ -229,12 +199,10 @@ macro_rules! define_bignum {
             /// Multiplies itself by a digit-sized `other` and returns its own
             /// mutable reference.
             pub fn mul_small(&mut self, other: $ty) -> &mut $name {
-                use crate::num::bignum::FullOps;
-
                 let mut sz = self.size;
                 let mut carry = 0;
                 for a in &mut self.base[..sz] {
-                    let (c, v) = (*a).full_mul(other, carry);
+                    let (v, c) = (*a).carrying_mul(other, carry);
                     *a = v;
                     carry = c;
                 }
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 85ceede5b9e..0b8ed0cc174 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -675,7 +675,7 @@ impl f32 {
     /// Returns the maximum of the two numbers.
     ///
     /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmin.
+    /// This matches the behavior of libm’s fmax.
     ///
     /// ```
     /// let x = 1.0f32;
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 4049c95b130..5a3cd2a4b92 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -691,7 +691,7 @@ impl f64 {
     /// Returns the maximum of the two numbers.
     ///
     /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmin.
+    /// This matches the behavior of libm’s fmax.
     ///
     /// ```
     /// let x = 1.0_f64;
diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs
index a8455fb355b..cc26c04a5d4 100644
--- a/library/core/src/num/int_log10.rs
+++ b/library/core/src/num/int_log10.rs
@@ -1,141 +1,140 @@
-mod unchecked {
-    // 0 < val <= u8::MAX
-    #[inline]
-    pub const fn u8(val: u8) -> u32 {
-        let val = val as u32;
-
-        // For better performance, avoid branches by assembling the solution
-        // in the bits above the low 8 bits.
-
-        // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
-        const C1: u32 = 0b11_00000000 - 10; // 758
-        // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
-        const C2: u32 = 0b10_00000000 - 100; // 412
-
-        // Value of top bits:
-        //            +c1  +c2  1&2
-        //     0..=9   10   01   00 = 0
-        //   10..=99   11   01   01 = 1
-        // 100..=255   11   10   10 = 2
-        ((val + C1) & (val + C2)) >> 8
-    }
+/// These functions compute the integer logarithm of their type, assuming
+/// that someone has already checked that the the value is strictly positive.
+
+// 0 < val <= u8::MAX
+#[inline]
+pub const fn u8(val: u8) -> u32 {
+    let val = val as u32;
+
+    // For better performance, avoid branches by assembling the solution
+    // in the bits above the low 8 bits.
+
+    // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
+    const C1: u32 = 0b11_00000000 - 10; // 758
+    // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
+    const C2: u32 = 0b10_00000000 - 100; // 412
+
+    // Value of top bits:
+    //            +c1  +c2  1&2
+    //     0..=9   10   01   00 = 0
+    //   10..=99   11   01   01 = 1
+    // 100..=255   11   10   10 = 2
+    ((val + C1) & (val + C2)) >> 8
+}
 
-    // 0 < val < 100_000
-    #[inline]
-    const fn less_than_5(val: u32) -> u32 {
-        // Similar to u8, when adding one of these constants to val,
-        // we get two possible bit patterns above the low 17 bits,
-        // depending on whether val is below or above the threshold.
-        const C1: u32 = 0b011_00000000000000000 - 10; // 393206
-        const C2: u32 = 0b100_00000000000000000 - 100; // 524188
-        const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
-        const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
-
-        // Value of top bits:
-        //                +c1  +c2  1&2  +c3  +c4  3&4   ^
-        //         0..=9  010  011  010  110  011  010  000 = 0
-        //       10..=99  011  011  011  110  011  010  001 = 1
-        //     100..=999  011  100  000  110  011  010  010 = 2
-        //   1000..=9999  011  100  000  111  011  011  011 = 3
-        // 10000..=99999  011  100  000  111  100  100  100 = 4
-        (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
-    }
+// 0 < val < 100_000
+#[inline]
+const fn less_than_5(val: u32) -> u32 {
+    // Similar to u8, when adding one of these constants to val,
+    // we get two possible bit patterns above the low 17 bits,
+    // depending on whether val is below or above the threshold.
+    const C1: u32 = 0b011_00000000000000000 - 10; // 393206
+    const C2: u32 = 0b100_00000000000000000 - 100; // 524188
+    const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
+    const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
+
+    // Value of top bits:
+    //                +c1  +c2  1&2  +c3  +c4  3&4   ^
+    //         0..=9  010  011  010  110  011  010  000 = 0
+    //       10..=99  011  011  011  110  011  010  001 = 1
+    //     100..=999  011  100  000  110  011  010  010 = 2
+    //   1000..=9999  011  100  000  111  011  011  011 = 3
+    // 10000..=99999  011  100  000  111  100  100  100 = 4
+    (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
+}
 
-    // 0 < val <= u16::MAX
-    #[inline]
-    pub const fn u16(val: u16) -> u32 {
-        less_than_5(val as u32)
-    }
+// 0 < val <= u16::MAX
+#[inline]
+pub const fn u16(val: u16) -> u32 {
+    less_than_5(val as u32)
+}
 
-    // 0 < val <= u32::MAX
-    #[inline]
-    pub const fn u32(mut val: u32) -> u32 {
-        let mut log = 0;
-        if val >= 100_000 {
-            val /= 100_000;
-            log += 5;
-        }
-        log + less_than_5(val)
+// 0 < val <= u32::MAX
+#[inline]
+pub const fn u32(mut val: u32) -> u32 {
+    let mut log = 0;
+    if val >= 100_000 {
+        val /= 100_000;
+        log += 5;
     }
+    log + less_than_5(val)
+}
 
-    // 0 < val <= u64::MAX
-    #[inline]
-    pub const fn u64(mut val: u64) -> u32 {
-        let mut log = 0;
-        if val >= 10_000_000_000 {
-            val /= 10_000_000_000;
-            log += 10;
-        }
-        if val >= 100_000 {
-            val /= 100_000;
-            log += 5;
-        }
-        log + less_than_5(val as u32)
+// 0 < val <= u64::MAX
+#[inline]
+pub const fn u64(mut val: u64) -> u32 {
+    let mut log = 0;
+    if val >= 10_000_000_000 {
+        val /= 10_000_000_000;
+        log += 10;
     }
-
-    // 0 < val <= u128::MAX
-    #[inline]
-    pub const fn u128(mut val: u128) -> u32 {
-        let mut log = 0;
-        if val >= 100_000_000_000_000_000_000_000_000_000_000 {
-            val /= 100_000_000_000_000_000_000_000_000_000_000;
-            log += 32;
-            return log + u32(val as u32);
-        }
-        if val >= 10_000_000_000_000_000 {
-            val /= 10_000_000_000_000_000;
-            log += 16;
-        }
-        log + u64(val as u64)
+    if val >= 100_000 {
+        val /= 100_000;
+        log += 5;
     }
+    log + less_than_5(val as u32)
+}
 
-    // 0 < val <= i8::MAX
-    #[inline]
-    pub const fn i8(val: i8) -> u32 {
-        u8(val as u8)
+// 0 < val <= u128::MAX
+#[inline]
+pub const fn u128(mut val: u128) -> u32 {
+    let mut log = 0;
+    if val >= 100_000_000_000_000_000_000_000_000_000_000 {
+        val /= 100_000_000_000_000_000_000_000_000_000_000;
+        log += 32;
+        return log + u32(val as u32);
     }
-
-    // 0 < val <= i16::MAX
-    #[inline]
-    pub const fn i16(val: i16) -> u32 {
-        u16(val as u16)
+    if val >= 10_000_000_000_000_000 {
+        val /= 10_000_000_000_000_000;
+        log += 16;
     }
+    log + u64(val as u64)
+}
 
-    // 0 < val <= i32::MAX
-    #[inline]
-    pub const fn i32(val: i32) -> u32 {
-        u32(val as u32)
-    }
+#[cfg(target_pointer_width = "16")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+    u16(val as _)
+}
 
-    // 0 < val <= i64::MAX
-    #[inline]
-    pub const fn i64(val: i64) -> u32 {
-        u64(val as u64)
-    }
+#[cfg(target_pointer_width = "32")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+    u32(val as _)
+}
 
-    // 0 < val <= i128::MAX
-    #[inline]
-    pub const fn i128(val: i128) -> u32 {
-        u128(val as u128)
-    }
+#[cfg(target_pointer_width = "64")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+    u64(val as _)
+}
+
+// 0 < val <= i8::MAX
+#[inline]
+pub const fn i8(val: i8) -> u32 {
+    u8(val as u8)
 }
 
-macro_rules! impl_checked {
-    ($T:ident) => {
-        #[inline]
-        pub const fn $T(val: $T) -> Option<u32> {
-            if val > 0 { Some(unchecked::$T(val)) } else { None }
-        }
-    };
+// 0 < val <= i16::MAX
+#[inline]
+pub const fn i16(val: i16) -> u32 {
+    u16(val as u16)
 }
 
-impl_checked! { u8 }
-impl_checked! { u16 }
-impl_checked! { u32 }
-impl_checked! { u64 }
-impl_checked! { u128 }
-impl_checked! { i8 }
-impl_checked! { i16 }
-impl_checked! { i32 }
-impl_checked! { i64 }
-impl_checked! { i128 }
+// 0 < val <= i32::MAX
+#[inline]
+pub const fn i32(val: i32) -> u32 {
+    u32(val as u32)
+}
+
+// 0 < val <= i64::MAX
+#[inline]
+pub const fn i64(val: i64) -> u32 {
+    u64(val as u64)
+}
+
+// 0 < val <= i128::MAX
+#[inline]
+pub const fn i128(val: i128) -> u32 {
+    u128(val as u128)
+}
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 6f7c5a6d119..79436c8e8ed 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2362,7 +2362,11 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         pub const fn checked_log10(self) -> Option<u32> {
-            int_log10::$ActualT(self as $ActualT)
+            if self > 0 {
+                Some(int_log10::$ActualT(self as $ActualT))
+            } else {
+                None
+            }
         }
 
         /// Computes the absolute value of `self`.
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index e3eab07b9df..721c030b410 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -264,7 +264,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000;
 
 #[lang = "u8"]
 impl u8 {
-    uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
+    uint_impl! { u8, u8, i8, NonZeroU8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
     "[0x12]", "", "" }
     widening_impl! { u8, u16, 8, unsigned }
 
@@ -813,21 +813,21 @@ impl u8 {
 
 #[lang = "u16"]
 impl u16 {
-    uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
     widening_impl! { u16, u32, 16, unsigned }
 }
 
 #[lang = "u32"]
 impl u32 {
-    uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { u32, u32, i32, NonZeroU32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
     widening_impl! { u32, u64, 32, unsigned }
 }
 
 #[lang = "u64"]
 impl u64 {
-    uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { u64, u64, i64, NonZeroU64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -837,7 +837,7 @@ impl u64 {
 
 #[lang = "u128"]
 impl u128 {
-    uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16,
+    uint_impl! { u128, u128, i128, NonZeroU128, 128, 340282366920938463463374607431768211455, 16,
     "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
     "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
     "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -850,7 +850,7 @@ impl u128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { usize, u16, isize, NonZeroUsize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
     widening_impl! { usize, u32, 16, unsigned }
@@ -858,7 +858,7 @@ impl usize {
 #[cfg(target_pointer_width = "32")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { usize, u32, isize, NonZeroUsize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
     widening_impl! { usize, u64, 32, unsigned }
@@ -867,7 +867,7 @@ impl usize {
 #[cfg(target_pointer_width = "64")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { usize, u64, isize, NonZeroUsize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 8f895c33a63..e21ae489179 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -302,7 +302,7 @@ nonzero_integers_div! {
 
 // A bunch of methods for unsigned nonzero types only.
 macro_rules! nonzero_unsigned_operations {
-    ( $( $Ty: ident($Int: ty); )+ ) => {
+    ( $( $Ty: ident($Int: ident); )+ ) => {
         $(
             impl $Ty {
                 /// Add an unsigned integer to a non-zero value.
@@ -442,6 +442,56 @@ macro_rules! nonzero_unsigned_operations {
                         None
                     }
                 }
+
+                /// Returns the base 2 logarithm of the number, rounded down.
+                ///
+                /// This is the same operation as
+                #[doc = concat!("[`", stringify!($Int), "::log2`],")]
+                /// except that it has no failure cases to worry about
+                /// since this value can never be zero.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(int_log)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")]
+                /// ```
+                #[unstable(feature = "int_log", issue = "70887")]
+                #[must_use = "this returns the result of the operation, \
+                              without modifying the original"]
+                #[inline]
+                pub const fn log2(self) -> u32 {
+                    <$Int>::BITS - 1 - self.leading_zeros()
+                }
+
+                /// Returns the base 10 logarithm of the number, rounded down.
+                ///
+                /// This is the same operation as
+                #[doc = concat!("[`", stringify!($Int), "::log10`],")]
+                /// except that it has no failure cases to worry about
+                /// since this value can never be zero.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(int_log)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")]
+                /// ```
+                #[unstable(feature = "int_log", issue = "70887")]
+                #[must_use = "this returns the result of the operation, \
+                              without modifying the original"]
+                #[inline]
+                pub const fn log10(self) -> u32 {
+                    super::int_log10::$Int(self.0)
+                }
             }
         )+
     }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 1dd8b0a18ab..0bb65497776 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1,5 +1,6 @@
 macro_rules! uint_impl {
-    ($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr,
+    ($SelfT:ty, $ActualT:ident, $SignedT:ident, $NonZeroT:ident,
+        $BITS:expr, $MaxV:expr,
         $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
         $reversed:expr, $le_bytes:expr, $be_bytes:expr,
         $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
@@ -839,12 +840,10 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         pub const fn checked_log2(self) -> Option<u32> {
-            if self <= 0 {
-                None
+            if let Some(x) = <$NonZeroT>::new(self) {
+                Some(x.log2())
             } else {
-                // SAFETY: We just checked that this number is positive
-                let log = (Self::BITS - 1) - unsafe { intrinsics::ctlz_nonzero(self) as u32 };
-                Some(log)
+                None
             }
         }
 
@@ -863,7 +862,11 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         pub const fn checked_log10(self) -> Option<u32> {
-            int_log10::$ActualT(self as $ActualT)
+            if let Some(x) = <$NonZeroT>::new(self) {
+                Some(x.log10())
+            } else {
+                None
+            }
         }
 
         /// Checked negation. Computes `-self`, returning `None` unless `self ==
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 8adfb6f4bcf..611f4ab38ab 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -551,6 +551,29 @@ impl<T> Option<T> {
         matches!(*self, Some(_))
     }
 
+    /// Returns `true` if the option is a [`Some`] wrapping a value matching the predicate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(is_some_with)]
+    ///
+    /// let x: Option<u32> = Some(2);
+    /// assert_eq!(x.is_some_with(|&x| x > 1), true);
+    ///
+    /// let x: Option<u32> = Some(0);
+    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    ///
+    /// let x: Option<u32> = None;
+    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "is_some_with", issue = "93050")]
+    pub fn is_some_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+        matches!(self, Some(x) if f(x))
+    }
+
     /// Returns `true` if the option is a [`None`] value.
     ///
     /// # Examples
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index b8f0d84746c..fbd6d419236 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -542,6 +542,29 @@ impl<T, E> Result<T, E> {
         matches!(*self, Ok(_))
     }
 
+    /// Returns `true` if the result is [`Ok`] wrapping a value matching the predicate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(is_some_with)]
+    ///
+    /// let x: Result<u32, &str> = Ok(2);
+    /// assert_eq!(x.is_ok_with(|&x| x > 1), true);
+    ///
+    /// let x: Result<u32, &str> = Ok(0);
+    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    ///
+    /// let x: Result<u32, &str> = Err("hey");
+    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "is_some_with", issue = "93050")]
+    pub fn is_ok_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+        matches!(self, Ok(x) if f(x))
+    }
+
     /// Returns `true` if the result is [`Err`].
     ///
     /// # Examples
@@ -563,6 +586,30 @@ impl<T, E> Result<T, E> {
         !self.is_ok()
     }
 
+    /// Returns `true` if the result is [`Err`] wrapping a value matching the predicate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(is_some_with)]
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));
+    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), true);
+    ///
+    /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));
+    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    ///
+    /// let x: Result<u32, Error> = Ok(123);
+    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "is_some_with", issue = "93050")]
+    pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool {
+        matches!(self, Err(x) if f(x))
+    }
+
     /////////////////////////////////////////////////////////////////////////
     // Adapter for each variant
     /////////////////////////////////////////////////////////////////////////
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 27243d8ca70..792016902ae 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -131,6 +131,7 @@ use crate::hint::spin_loop;
 /// loads and stores of `u8`.
 #[cfg(target_has_atomic_load_store = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "AtomicBool"]
 #[repr(C, align(1))]
 pub struct AtomicBool {
     v: UnsafeCell<u8>,
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 9c1b79d6966..d859bff1a45 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -373,38 +373,61 @@ impl CString {
     /// the position of the nul byte.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
-        trait SpecIntoVec {
-            fn into_vec(self) -> Vec<u8>;
+        trait SpecNewImpl {
+            fn spec_new_impl(self) -> Result<CString, NulError>;
         }
-        impl<T: Into<Vec<u8>>> SpecIntoVec for T {
-            default fn into_vec(self) -> Vec<u8> {
-                self.into()
+
+        impl<T: Into<Vec<u8>>> SpecNewImpl for T {
+            default fn spec_new_impl(self) -> Result<CString, NulError> {
+                let bytes: Vec<u8> = self.into();
+                match memchr::memchr(0, &bytes) {
+                    Some(i) => Err(NulError(i, bytes)),
+                    None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+                }
             }
         }
-        // Specialization for avoiding reallocation.
-        impl SpecIntoVec for &'_ [u8] {
-            fn into_vec(self) -> Vec<u8> {
-                let mut v = Vec::with_capacity(self.len() + 1);
-                v.extend(self);
-                v
+
+        // Specialization for avoiding reallocation
+        #[inline(always)] // Without that it is not inlined into specializations
+        fn spec_new_impl_bytes(bytes: &[u8]) -> Result<CString, NulError> {
+            // We cannot have such large slice that we would overflow here
+            // but using `checked_add` allows LLVM to assume that capacity never overflows
+            // and generate twice shorter code.
+            // `saturating_add` doesn't help for some reason.
+            let capacity = bytes.len().checked_add(1).unwrap();
+
+            // Allocate before validation to avoid duplication of allocation code.
+            // We still need to allocate and copy memory even if we get an error.
+            let mut buffer = Vec::with_capacity(capacity);
+            buffer.extend(bytes);
+
+            // Check memory of self instead of new buffer.
+            // This allows better optimizations if lto enabled.
+            match memchr::memchr(0, bytes) {
+                Some(i) => Err(NulError(i, buffer)),
+                None => Ok(unsafe { CString::from_vec_unchecked(buffer) }),
             }
         }
-        impl SpecIntoVec for &'_ str {
-            fn into_vec(self) -> Vec<u8> {
-                let mut v = Vec::with_capacity(self.len() + 1);
-                v.extend(self.as_bytes());
-                v
+
+        impl SpecNewImpl for &'_ [u8] {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self)
             }
         }
 
-        Self::_new(SpecIntoVec::into_vec(t))
-    }
+        impl SpecNewImpl for &'_ str {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self.as_bytes())
+            }
+        }
 
-    fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
-        match memchr::memchr(0, &bytes) {
-            Some(i) => Err(NulError(i, bytes)),
-            None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+        impl SpecNewImpl for &'_ mut [u8] {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self)
+            }
         }
+
+        t.spec_new_impl()
     }
 
     /// Creates a C-compatible string by consuming a byte vector,
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index a00b5e12323..9d6b2fe8c25 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1050,7 +1050,7 @@ impl Metadata {
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let link_path = Path::new("link");
-    ///     symlink("/origin_does_not_exists/", link_path)?;
+    ///     symlink("/origin_does_not_exist/", link_path)?;
     ///
     ///     let metadata = fs::symlink_metadata(link_path)?;
     ///
@@ -2042,13 +2042,17 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///
 /// # Platform-specific behavior
 ///
-/// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix
-/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
-/// on Windows.
-/// Note that, this [may change in the future][changes].
+/// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions
+/// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`,
+/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtOpenFile` functions on
+/// Windows. Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
 ///
+/// On macOS before version 10.10 and REDOX this function is not protected against time-of-check to
+/// time-of-use (TOCTOU) race conditions, and should not be used in security-sensitive code on
+/// those platforms. All other platforms are protected.
+///
 /// # Errors
 ///
 /// See [`fs::remove_file`] and [`fs::remove_dir`].
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 749d51d4981..a62c01ef29b 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -4,8 +4,10 @@ use crate::fs::{self, File, OpenOptions};
 use crate::io::{ErrorKind, SeekFrom};
 use crate::path::Path;
 use crate::str;
+use crate::sync::Arc;
 use crate::sys_common::io::test::{tmpdir, TempDir};
 use crate::thread;
+use crate::time::{Duration, Instant};
 
 use rand::{rngs::StdRng, RngCore, SeedableRng};
 
@@ -602,6 +604,21 @@ fn recursive_rmdir_of_symlink() {
 }
 
 #[test]
+fn recursive_rmdir_of_file_fails() {
+    // test we do not delete a directly specified file.
+    let tmpdir = tmpdir();
+    let canary = tmpdir.join("do_not_delete");
+    check!(check!(File::create(&canary)).write(b"foo"));
+    let result = fs::remove_dir_all(&canary);
+    #[cfg(unix)]
+    error!(result, "Not a directory");
+    #[cfg(windows)]
+    error!(result, 267); // ERROR_DIRECTORY - The directory name is invalid.
+    assert!(result.is_err());
+    assert!(canary.exists());
+}
+
+#[test]
 // only Windows makes a distinction between file and directory symlinks.
 #[cfg(windows)]
 fn recursive_rmdir_of_file_symlink() {
@@ -621,6 +638,59 @@ fn recursive_rmdir_of_file_symlink() {
 }
 
 #[test]
+#[ignore] // takes too much time
+fn recursive_rmdir_toctou() {
+    // Test for time-of-check to time-of-use issues.
+    //
+    // Scenario:
+    // The attacker wants to get directory contents deleted, to which he does not have access.
+    // He has a way to get a privileged Rust binary call `std::fs::remove_dir_all()` on a
+    // directory he controls, e.g. in his home directory.
+    //
+    // The POC sets up the `attack_dest/attack_file` which the attacker wants to have deleted.
+    // The attacker repeatedly creates a directory and replaces it with a symlink from
+    // `victim_del` to `attack_dest` while the victim code calls `std::fs::remove_dir_all()`
+    // on `victim_del`. After a few seconds the attack has succeeded and
+    // `attack_dest/attack_file` is deleted.
+    let tmpdir = tmpdir();
+    let victim_del_path = tmpdir.join("victim_del");
+    let victim_del_path_clone = victim_del_path.clone();
+
+    // setup dest
+    let attack_dest_dir = tmpdir.join("attack_dest");
+    let attack_dest_dir = attack_dest_dir.as_path();
+    fs::create_dir(attack_dest_dir).unwrap();
+    let attack_dest_file = tmpdir.join("attack_dest/attack_file");
+    File::create(&attack_dest_file).unwrap();
+
+    let drop_canary_arc = Arc::new(());
+    let drop_canary_weak = Arc::downgrade(&drop_canary_arc);
+
+    eprintln!("x: {:?}", &victim_del_path);
+
+    // victim just continuously removes `victim_del`
+    thread::spawn(move || {
+        while drop_canary_weak.upgrade().is_some() {
+            let _ = fs::remove_dir_all(&victim_del_path_clone);
+        }
+    });
+
+    // attacker (could of course be in a separate process)
+    let start_time = Instant::now();
+    while Instant::now().duration_since(start_time) < Duration::from_secs(1000) {
+        if !attack_dest_file.exists() {
+            panic!(
+                "Victim deleted symlinked file outside of victim_del. Attack succeeded in {:?}.",
+                Instant::now().duration_since(start_time)
+            );
+        }
+        let _ = fs::create_dir(&victim_del_path);
+        let _ = fs::remove_dir(&victim_del_path);
+        let _ = symlink_dir(attack_dest_dir, &victim_del_path);
+    }
+}
+
+#[test]
 fn unicode_path_is_dir() {
     assert!(Path::new(".").is_dir());
     assert!(!Path::new("test/stdtest/fs.rs").is_dir());
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 4f630dcb04d..17fe0011569 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -340,7 +340,6 @@
 #![feature(unboxed_closures)]
 #![feature(unwrap_infallible)]
 #![feature(vec_into_raw_parts)]
-#![feature(vec_spare_capacity)]
 // NB: the above list is sorted to minimize merge conflicts.
 #![default_lib_allocator]
 
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 44f573297ee..d0f332fe5e8 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -263,7 +263,7 @@ fn default_hook(info: &PanicInfo<'_>) {
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
     let backtrace_env = if panic_count::get_count() >= 2 {
-        RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full)
+        backtrace::rust_backtrace_print_full()
     } else {
         backtrace::rust_backtrace_env()
     };
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 7d401cff591..f509403fe2e 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2806,7 +2806,7 @@ impl Path {
     /// use std::os::unix::fs::symlink;
     ///
     /// let link_path = Path::new("link");
-    /// symlink("/origin_does_not_exists/", link_path).unwrap();
+    /// symlink("/origin_does_not_exist/", link_path).unwrap();
     /// assert_eq!(link_path.is_symlink(), true);
     /// assert_eq!(link_path.exists(), false);
     /// ```
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index bcf2be0e95f..f8deda93fe2 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -64,7 +64,7 @@ use libc::{
     dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64,
 };
 
-pub use crate::sys_common::fs::{remove_dir_all, try_exists};
+pub use crate::sys_common::fs::try_exists;
 
 pub struct File(FileDesc);
 
@@ -228,7 +228,7 @@ pub struct DirEntry {
         target_os = "fuchsia",
         target_os = "redox"
     ))]
-    name: Box<[u8]>,
+    name: CString,
 }
 
 #[derive(Clone, Debug)]
@@ -455,8 +455,6 @@ impl Iterator for ReadDir {
         target_os = "illumos"
     ))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
-        use crate::slice;
-
         unsafe {
             loop {
                 // Although readdir_r(3) would be a correct function to use here because
@@ -474,14 +472,10 @@ impl Iterator for ReadDir {
                     };
                 }
 
-                let name = (*entry_ptr).d_name.as_ptr();
-                let namelen = libc::strlen(name) as usize;
-
                 let ret = DirEntry {
                     entry: *entry_ptr,
-                    name: slice::from_raw_parts(name as *const u8, namelen as usize)
-                        .to_owned()
-                        .into_boxed_slice(),
+                    // d_name is guaranteed to be null-terminated.
+                    name: CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(),
                     dir: Arc::clone(&self.inner),
                 };
                 if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
@@ -664,7 +658,21 @@ impl DirEntry {
         target_os = "redox"
     ))]
     fn name_bytes(&self) -> &[u8] {
-        &*self.name
+        self.name.as_bytes()
+    }
+
+    #[cfg(not(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "fuchsia",
+        target_os = "redox"
+    )))]
+    fn name_cstr(&self) -> &CStr {
+        unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
+    }
+    #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "fuchsia"))]
+    fn name_cstr(&self) -> &CStr {
+        &self.name
     }
 
     pub fn file_name_os_str(&self) -> &OsStr {
@@ -1437,3 +1445,258 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
     cvt(unsafe { libc::chroot(dir.as_ptr()) })?;
     Ok(())
 }
+
+pub use remove_dir_impl::remove_dir_all;
+
+// Fallback for REDOX
+#[cfg(target_os = "redox")]
+mod remove_dir_impl {
+    pub use crate::sys_common::fs::remove_dir_all;
+}
+
+// Dynamically choose implementation Macos x86-64: modern for 10.10+, fallback for older versions
+#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
+mod remove_dir_impl {
+    use super::{cstr, lstat, Dir, InnerReadDir, ReadDir};
+    use crate::ffi::CStr;
+    use crate::io;
+    use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+    use crate::os::unix::prelude::{OwnedFd, RawFd};
+    use crate::path::{Path, PathBuf};
+    use crate::sync::Arc;
+    use crate::sys::weak::weak;
+    use crate::sys::{cvt, cvt_r};
+    use libc::{c_char, c_int, DIR};
+
+    pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
+        weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
+        let fd = cvt_r(|| unsafe {
+            openat.get().unwrap()(
+                parent_fd.unwrap_or(libc::AT_FDCWD),
+                p.as_ptr(),
+                libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY,
+            )
+        })?;
+        Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+    }
+
+    fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
+        weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64");
+        let ptr = unsafe { fdopendir.get().unwrap()(dir_fd.as_raw_fd()) };
+        if ptr.is_null() {
+            return Err(io::Error::last_os_error());
+        }
+        let dirp = Dir(ptr);
+        // file descriptor is automatically closed by libc::closedir() now, so give up ownership
+        let new_parent_fd = dir_fd.into_raw_fd();
+        // a valid root is not needed because we do not call any functions involving the full path
+        // of the DirEntrys.
+        let dummy_root = PathBuf::new();
+        Ok((
+            ReadDir {
+                inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
+                end_of_stream: false,
+            },
+            new_parent_fd,
+        ))
+    }
+
+    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
+        weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int);
+
+        let pcstr = cstr(p)?;
+
+        // entry is expected to be a directory, open as such
+        let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+
+        // open the directory passing ownership of the fd
+        let (dir, fd) = fdreaddir(fd)?;
+        for child in dir {
+            let child = child?;
+            match child.entry.d_type {
+                libc::DT_DIR => {
+                    remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                }
+                libc::DT_UNKNOWN => {
+                    match cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })
+                    {
+                        // type unknown - try to unlink
+                        Err(err) if err.raw_os_error() == Some(libc::EPERM) => {
+                            // if the file is a directory unlink fails with EPERM
+                            remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                        }
+                        result => {
+                            result?;
+                        }
+                    }
+                }
+                _ => {
+                    // not a directory -> unlink
+                    cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })?;
+                }
+            }
+        }
+
+        // unlink the directory after removing its contents
+        cvt(unsafe {
+            unlinkat.get().unwrap()(
+                parent_fd.unwrap_or(libc::AT_FDCWD),
+                pcstr.as_ptr(),
+                libc::AT_REMOVEDIR,
+            )
+        })?;
+        Ok(())
+    }
+
+    fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
+        // We cannot just call remove_dir_all_recursive() here because that would not delete a passed
+        // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
+        // into symlinks.
+        let attr = lstat(p)?;
+        if attr.file_type().is_symlink() {
+            crate::fs::remove_file(p)
+        } else {
+            remove_dir_all_recursive(None, p)
+        }
+    }
+
+    pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+        weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
+        if openat.get().is_some() {
+            // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir()
+            remove_dir_all_modern(p)
+        } else {
+            // fall back to classic implementation
+            crate::sys_common::fs::remove_dir_all(p)
+        }
+    }
+}
+
+// Modern implementation using openat(), unlinkat() and fdopendir()
+#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = "redox")))]
+mod remove_dir_impl {
+    use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
+    use crate::ffi::CStr;
+    use crate::io;
+    use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+    use crate::os::unix::prelude::{OwnedFd, RawFd};
+    use crate::path::{Path, PathBuf};
+    use crate::sync::Arc;
+    use crate::sys::{cvt, cvt_r};
+    use libc::{fdopendir, openat, unlinkat};
+
+    pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
+        let fd = cvt_r(|| unsafe {
+            openat(
+                parent_fd.unwrap_or(libc::AT_FDCWD),
+                p.as_ptr(),
+                libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY,
+            )
+        })?;
+        Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+    }
+
+    fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
+        let ptr = unsafe { fdopendir(dir_fd.as_raw_fd()) };
+        if ptr.is_null() {
+            return Err(io::Error::last_os_error());
+        }
+        let dirp = Dir(ptr);
+        // file descriptor is automatically closed by libc::closedir() now, so give up ownership
+        let new_parent_fd = dir_fd.into_raw_fd();
+        // a valid root is not needed because we do not call any functions involving the full path
+        // of the DirEntrys.
+        let dummy_root = PathBuf::new();
+        Ok((
+            ReadDir {
+                inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
+                #[cfg(not(any(
+                    target_os = "solaris",
+                    target_os = "illumos",
+                    target_os = "fuchsia",
+                    target_os = "redox",
+                )))]
+                end_of_stream: false,
+            },
+            new_parent_fd,
+        ))
+    }
+
+    #[cfg(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "haiku",
+        target_os = "vxworks",
+        target_os = "fuchsia"
+    ))]
+    fn is_dir(_ent: &DirEntry) -> Option<bool> {
+        None
+    }
+
+    #[cfg(not(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "haiku",
+        target_os = "vxworks",
+        target_os = "fuchsia"
+    )))]
+    fn is_dir(ent: &DirEntry) -> Option<bool> {
+        match ent.entry.d_type {
+            libc::DT_UNKNOWN => None,
+            libc::DT_DIR => Some(true),
+            _ => Some(false),
+        }
+    }
+
+    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
+        let pcstr = cstr(p)?;
+
+        // entry is expected to be a directory, open as such
+        let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+
+        // open the directory passing ownership of the fd
+        let (dir, fd) = fdreaddir(fd)?;
+        for child in dir {
+            let child = child?;
+            match is_dir(&child) {
+                Some(true) => {
+                    remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                }
+                Some(false) => {
+                    cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?;
+                }
+                None => match cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) }) {
+                    // type unknown - try to unlink
+                    Err(err)
+                        if err.raw_os_error() == Some(libc::EISDIR)
+                            || err.raw_os_error() == Some(libc::EPERM) =>
+                    {
+                        // if the file is a directory unlink fails with EISDIR on Linux and EPERM everyhwere else
+                        remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                    }
+                    result => {
+                        result?;
+                    }
+                },
+            }
+        }
+
+        // unlink the directory after removing its contents
+        cvt(unsafe {
+            unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR)
+        })?;
+        Ok(())
+    }
+
+    pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+        // We cannot just call remove_dir_all_recursive() here because that would not delete a passed
+        // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
+        // into symlinks.
+        let attr = lstat(p)?;
+        if attr.file_type().is_symlink() {
+            crate::fs::remove_file(p)
+        } else {
+            remove_dir_all_recursive(None, p)
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index 55719b87c7e..da63c068384 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -73,12 +73,14 @@ impl<F> ExternWeak<F> {
 
 pub(crate) macro dlsym {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+         dlsym!(fn $name($($t),*) -> $ret, stringify!($name));
+    ),
+    (fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => (
         static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
-            DlsymWeak::new(concat!(stringify!($name), '\0'));
+            DlsymWeak::new(concat!($sym, '\0'));
         let $name = &DLSYM;
     )
 }
-
 pub(crate) struct DlsymWeak<F> {
     name: &'static str,
     addr: AtomicUsize,
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 1a3da3746ac..5924789d12b 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -16,7 +16,7 @@ use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
-pub use crate::sys_common::fs::{remove_dir_all, try_exists};
+pub use crate::sys_common::fs::try_exists;
 
 pub struct File {
     fd: WasiFd,
@@ -130,6 +130,18 @@ impl FileType {
     }
 }
 
+impl ReadDir {
+    fn new(dir: File, root: PathBuf) -> ReadDir {
+        ReadDir {
+            cookie: Some(0),
+            buf: vec![0; 128],
+            offset: 0,
+            cap: 0,
+            inner: Arc::new(ReadDirInner { dir, root }),
+        }
+    }
+}
+
 impl fmt::Debug for ReadDir {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("ReadDir").finish_non_exhaustive()
@@ -516,13 +528,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
     opts.directory(true);
     opts.read(true);
     let dir = File::open(p, &opts)?;
-    Ok(ReadDir {
-        cookie: Some(0),
-        buf: vec![0; 128],
-        offset: 0,
-        cap: 0,
-        inner: Arc::new(ReadDirInner { dir, root: p.to_path_buf() }),
-    })
+    Ok(ReadDir::new(dir, p.to_path_buf()))
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
@@ -716,3 +722,52 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
 
     io::copy(&mut reader, &mut writer)
 }
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+    let (parent, path) = open_parent(path)?;
+    remove_dir_all_recursive(&parent, &path)
+}
+
+fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> {
+    // Open up a file descriptor for the directory itself. Note that we don't
+    // follow symlinks here and we specifically open directories.
+    //
+    // At the root invocation of this function this will correctly handle
+    // symlinks passed to the top-level `remove_dir_all`. At the recursive
+    // level this will double-check that after the `readdir` call deduced this
+    // was a directory it's still a directory by the time we open it up.
+    //
+    // If the opened file was actually a symlink then the symlink is deleted,
+    // not the directory recursively.
+    let mut opts = OpenOptions::new();
+    opts.lookup_flags(0);
+    opts.directory(true);
+    opts.read(true);
+    let fd = open_at(parent, path, &opts)?;
+    if fd.file_attr()?.file_type().is_symlink() {
+        return parent.unlink_file(osstr2str(path.as_ref())?);
+    }
+
+    // this "root" is only used by `DirEntry::path` which we don't use below so
+    // it's ok for this to be a bogus value
+    let dummy_root = PathBuf::new();
+
+    // Iterate over all the entries in this directory, and travel recursively if
+    // necessary
+    for entry in ReadDir::new(fd, dummy_root) {
+        let entry = entry?;
+        let path = crate::str::from_utf8(&entry.name).map_err(|_| {
+            io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found")
+        })?;
+
+        if entry.file_type()?.is_dir() {
+            remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?;
+        } else {
+            entry.inner.dir.fd.unlink_file(path)?;
+        }
+    }
+
+    // Once all this directory's contents are deleted it should be safe to
+    // delete the directory tiself.
+    parent.remove_directory(osstr2str(path.as_ref())?)
+}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index b87b6b5d88e..09d3661e4fd 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -4,6 +4,7 @@
 #![cfg_attr(test, allow(dead_code))]
 #![unstable(issue = "none", feature = "windows_c")]
 
+use crate::mem;
 use crate::os::raw::NonZero_c_ulong;
 use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
 use crate::ptr;
@@ -36,6 +37,7 @@ pub type USHORT = c_ushort;
 pub type SIZE_T = usize;
 pub type WORD = u16;
 pub type CHAR = c_char;
+pub type CCHAR = c_char;
 pub type ULONG_PTR = usize;
 pub type ULONG = c_ulong;
 pub type NTSTATUS = LONG;
@@ -86,16 +88,21 @@ pub const FILE_SHARE_DELETE: DWORD = 0x4;
 pub const FILE_SHARE_READ: DWORD = 0x1;
 pub const FILE_SHARE_WRITE: DWORD = 0x2;
 
+pub const FILE_OPEN_REPARSE_POINT: ULONG = 0x200000;
+pub const OBJ_DONT_REPARSE: ULONG = 0x1000;
+
 pub const CREATE_ALWAYS: DWORD = 2;
 pub const CREATE_NEW: DWORD = 1;
 pub const OPEN_ALWAYS: DWORD = 4;
 pub const OPEN_EXISTING: DWORD = 3;
 pub const TRUNCATE_EXISTING: DWORD = 5;
 
+pub const FILE_LIST_DIRECTORY: DWORD = 0x1;
 pub const FILE_WRITE_DATA: DWORD = 0x00000002;
 pub const FILE_APPEND_DATA: DWORD = 0x00000004;
 pub const FILE_WRITE_EA: DWORD = 0x00000010;
 pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+pub const DELETE: DWORD = 0x10000;
 pub const READ_CONTROL: DWORD = 0x00020000;
 pub const SYNCHRONIZE: DWORD = 0x00100000;
 pub const GENERIC_READ: DWORD = 0x80000000;
@@ -261,10 +268,62 @@ pub const FD_SETSIZE: usize = 64;
 pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
 
 pub const STATUS_SUCCESS: NTSTATUS = 0x00000000;
+pub const STATUS_DELETE_PENDING: NTSTATUS = 0xc0000056_u32 as _;
+pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _;
+
+// Equivalent to the `NT_SUCCESS` C preprocessor macro.
+// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
+pub fn nt_success(status: NTSTATUS) -> bool {
+    status >= 0
+}
 
 pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002;
 
 #[repr(C)]
+pub struct UNICODE_STRING {
+    pub Length: u16,
+    pub MaximumLength: u16,
+    pub Buffer: *mut u16,
+}
+impl UNICODE_STRING {
+    pub fn from_ref(slice: &[u16]) -> Self {
+        let len = slice.len() * mem::size_of::<u16>();
+        Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ }
+    }
+}
+#[repr(C)]
+pub struct OBJECT_ATTRIBUTES {
+    pub Length: ULONG,
+    pub RootDirectory: HANDLE,
+    pub ObjectName: *const UNICODE_STRING,
+    pub Attributes: ULONG,
+    pub SecurityDescriptor: *mut c_void,
+    pub SecurityQualityOfService: *mut c_void,
+}
+impl Default for OBJECT_ATTRIBUTES {
+    fn default() -> Self {
+        Self {
+            Length: mem::size_of::<Self>() as _,
+            RootDirectory: ptr::null_mut(),
+            ObjectName: ptr::null_mut(),
+            Attributes: 0,
+            SecurityDescriptor: ptr::null_mut(),
+            SecurityQualityOfService: ptr::null_mut(),
+        }
+    }
+}
+#[repr(C)]
+pub struct IO_STATUS_BLOCK {
+    pub Pointer: *mut c_void,
+    pub Information: usize,
+}
+impl Default for IO_STATUS_BLOCK {
+    fn default() -> Self {
+        Self { Pointer: ptr::null_mut(), Information: 0 }
+    }
+}
+
+#[repr(C)]
 #[cfg(not(target_pointer_width = "64"))]
 pub struct WSADATA {
     pub wVersion: WORD,
@@ -353,10 +412,44 @@ pub enum FILE_INFO_BY_HANDLE_CLASS {
     FileIdInfo = 18,                     // 0x12
     FileIdExtdDirectoryInfo = 19,        // 0x13
     FileIdExtdDirectoryRestartInfo = 20, // 0x14
+    FileDispositionInfoEx = 21,          // 0x15, Windows 10 version 1607
     MaximumFileInfoByHandlesClass,
 }
 
 #[repr(C)]
+pub struct FILE_DISPOSITION_INFO {
+    pub DeleteFile: BOOLEAN,
+}
+
+pub const FILE_DISPOSITION_DELETE: DWORD = 0x1;
+pub const FILE_DISPOSITION_POSIX_SEMANTICS: DWORD = 0x2;
+pub const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: DWORD = 0x10;
+
+#[repr(C)]
+pub struct FILE_DISPOSITION_INFO_EX {
+    pub Flags: DWORD,
+}
+
+#[repr(C)]
+#[derive(Default)]
+pub struct FILE_ID_BOTH_DIR_INFO {
+    pub NextEntryOffset: DWORD,
+    pub FileIndex: DWORD,
+    pub CreationTime: LARGE_INTEGER,
+    pub LastAccessTime: LARGE_INTEGER,
+    pub LastWriteTime: LARGE_INTEGER,
+    pub ChangeTime: LARGE_INTEGER,
+    pub EndOfFile: LARGE_INTEGER,
+    pub AllocationSize: LARGE_INTEGER,
+    pub FileAttributes: DWORD,
+    pub FileNameLength: DWORD,
+    pub EaSize: DWORD,
+    pub ShortNameLength: CCHAR,
+    pub ShortName: [WCHAR; 12],
+    pub FileId: LARGE_INTEGER,
+    pub FileName: [WCHAR; 1],
+}
+#[repr(C)]
 pub struct FILE_BASIC_INFO {
     pub CreationTime: LARGE_INTEGER,
     pub LastAccessTime: LARGE_INTEGER,
@@ -750,16 +843,6 @@ if #[cfg(target_vendor = "uwp")] {
         pub DeletePending: BOOLEAN,
         pub Directory: BOOLEAN,
     }
-
-    #[link(name = "kernel32")]
-    extern "system" {
-        pub fn GetFileInformationByHandleEx(
-            hFile: HANDLE,
-            fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
-            lpFileInformation: LPVOID,
-            dwBufferSize: DWORD,
-        ) -> BOOL;
-    }
 }
 }
 
@@ -949,6 +1032,12 @@ extern "system" {
         cchFilePath: DWORD,
         dwFlags: DWORD,
     ) -> DWORD;
+    pub fn GetFileInformationByHandleEx(
+        hFile: HANDLE,
+        fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
+        lpFileInformation: LPVOID,
+        dwBufferSize: DWORD,
+    ) -> BOOL;
     pub fn SetFileInformationByHandle(
         hFile: HANDLE,
         FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
@@ -1139,6 +1228,21 @@ compat_fn! {
 
 compat_fn! {
     "ntdll":
+    pub fn NtOpenFile(
+        FileHandle: *mut HANDLE,
+        DesiredAccess: ACCESS_MASK,
+        ObjectAttributes: *const OBJECT_ATTRIBUTES,
+        IoStatusBlock: *mut IO_STATUS_BLOCK,
+        ShareAccess: ULONG,
+        OpenOptions: ULONG
+    ) -> NTSTATUS {
+        panic!("`NtOpenFile` not available");
+    }
+    pub fn RtlNtStatusToDosError(
+        Status: NTSTATUS
+    ) -> ULONG {
+        panic!("`RtlNtStatusToDosError` not available");
+    }
     pub fn NtCreateKeyedEvent(
         KeyedEventHandle: LPHANDLE,
         DesiredAccess: ACCESS_MASK,
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index b258fc0478b..dd21c6b4389 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -547,6 +547,218 @@ impl File {
         })?;
         Ok(())
     }
+    /// Get only basic file information such as attributes and file times.
+    fn basic_info(&self) -> io::Result<c::FILE_BASIC_INFO> {
+        unsafe {
+            let mut info: c::FILE_BASIC_INFO = mem::zeroed();
+            let size = mem::size_of_val(&info);
+            cvt(c::GetFileInformationByHandleEx(
+                self.handle.as_raw_handle(),
+                c::FileBasicInfo,
+                &mut info as *mut _ as *mut libc::c_void,
+                size as c::DWORD,
+            ))?;
+            Ok(info)
+        }
+    }
+    /// Delete using POSIX semantics.
+    ///
+    /// Files will be deleted as soon as the handle is closed. This is supported
+    /// for Windows 10 1607 (aka RS1) and later. However some filesystem
+    /// drivers will not support it even then, e.g. FAT32.
+    ///
+    /// If the operation is not supported for this filesystem or OS version
+    /// then errors will be `ERROR_NOT_SUPPORTED` or `ERROR_INVALID_PARAMETER`.
+    fn posix_delete(&self) -> io::Result<()> {
+        let mut info = c::FILE_DISPOSITION_INFO_EX {
+            Flags: c::FILE_DISPOSITION_DELETE
+                | c::FILE_DISPOSITION_POSIX_SEMANTICS
+                | c::FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,
+        };
+        let size = mem::size_of_val(&info);
+        cvt(unsafe {
+            c::SetFileInformationByHandle(
+                self.handle.as_raw_handle(),
+                c::FileDispositionInfoEx,
+                &mut info as *mut _ as *mut _,
+                size as c::DWORD,
+            )
+        })?;
+        Ok(())
+    }
+
+    /// Delete a file using win32 semantics. The file won't actually be deleted
+    /// until all file handles are closed. However, marking a file for deletion
+    /// will prevent anyone from opening a new handle to the file.
+    fn win32_delete(&self) -> io::Result<()> {
+        let mut info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ };
+        let size = mem::size_of_val(&info);
+        cvt(unsafe {
+            c::SetFileInformationByHandle(
+                self.handle.as_raw_handle(),
+                c::FileDispositionInfo,
+                &mut info as *mut _ as *mut _,
+                size as c::DWORD,
+            )
+        })?;
+        Ok(())
+    }
+
+    /// Fill the given buffer with as many directory entries as will fit.
+    /// This will remember its position and continue from the last call unless
+    /// `restart` is set to `true`.
+    ///
+    /// The returned bool indicates if there are more entries or not.
+    /// It is an error if `self` is not a directory.
+    ///
+    /// # Symlinks and other reparse points
+    ///
+    /// On Windows a file is either a directory or a non-directory.
+    /// A symlink directory is simply an empty directory with some "reparse" metadata attached.
+    /// So if you open a link (not its target) and iterate the directory,
+    /// you will always iterate an empty directory regardless of the target.
+    fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> io::Result<bool> {
+        let class =
+            if restart { c::FileIdBothDirectoryRestartInfo } else { c::FileIdBothDirectoryInfo };
+
+        unsafe {
+            let result = cvt(c::GetFileInformationByHandleEx(
+                self.handle.as_raw_handle(),
+                class,
+                buffer.as_mut_ptr().cast(),
+                buffer.capacity() as _,
+            ));
+            match result {
+                Ok(_) => Ok(true),
+                Err(e) if e.raw_os_error() == Some(c::ERROR_NO_MORE_FILES as _) => Ok(false),
+                Err(e) => Err(e),
+            }
+        }
+    }
+}
+
+/// A buffer for holding directory entries.
+struct DirBuff {
+    buffer: Vec<u8>,
+}
+impl DirBuff {
+    fn new() -> Self {
+        const BUFFER_SIZE: usize = 1024;
+        Self { buffer: vec![0_u8; BUFFER_SIZE] }
+    }
+    fn capacity(&self) -> usize {
+        self.buffer.len()
+    }
+    fn as_mut_ptr(&mut self) -> *mut u8 {
+        self.buffer.as_mut_ptr().cast()
+    }
+    /// Returns a `DirBuffIter`.
+    fn iter(&self) -> DirBuffIter<'_> {
+        DirBuffIter::new(self)
+    }
+}
+impl AsRef<[u8]> for DirBuff {
+    fn as_ref(&self) -> &[u8] {
+        &self.buffer
+    }
+}
+
+/// An iterator over entries stored in a `DirBuff`.
+///
+/// Currently only returns file names (UTF-16 encoded).
+struct DirBuffIter<'a> {
+    buffer: Option<&'a [u8]>,
+    cursor: usize,
+}
+impl<'a> DirBuffIter<'a> {
+    fn new(buffer: &'a DirBuff) -> Self {
+        Self { buffer: Some(buffer.as_ref()), cursor: 0 }
+    }
+}
+impl<'a> Iterator for DirBuffIter<'a> {
+    type Item = &'a [u16];
+    fn next(&mut self) -> Option<Self::Item> {
+        use crate::mem::size_of;
+        let buffer = &self.buffer?[self.cursor..];
+
+        // Get the name and next entry from the buffer.
+        // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the
+        // last field (the file name) is unsized. So an offset has to be
+        // used to get the file name slice.
+        let (name, next_entry) = unsafe {
+            let info = buffer.as_ptr().cast::<c::FILE_ID_BOTH_DIR_INFO>();
+            let next_entry = (*info).NextEntryOffset as usize;
+            let name = crate::slice::from_raw_parts(
+                (*info).FileName.as_ptr().cast::<u16>(),
+                (*info).FileNameLength as usize / size_of::<u16>(),
+            );
+            (name, next_entry)
+        };
+
+        if next_entry == 0 {
+            self.buffer = None
+        } else {
+            self.cursor += next_entry
+        }
+
+        // Skip `.` and `..` pseudo entries.
+        const DOT: u16 = b'.' as u16;
+        match name {
+            [DOT] | [DOT, DOT] => self.next(),
+            _ => Some(name),
+        }
+    }
+}
+
+/// Open a link relative to the parent directory, ensure no symlinks are followed.
+fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<File> {
+    // This is implemented using the lower level `NtOpenFile` function as
+    // unfortunately opening a file relative to a parent is not supported by
+    // win32 functions. It is however a fundamental feature of the NT kernel.
+    //
+    // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile
+    unsafe {
+        let mut handle = ptr::null_mut();
+        let mut io_status = c::IO_STATUS_BLOCK::default();
+        let name_str = c::UNICODE_STRING::from_ref(name);
+        use crate::sync::atomic::{AtomicU32, Ordering};
+        // The `OBJ_DONT_REPARSE` attribute ensures that we haven't been
+        // tricked into following a symlink. However, it may not be available in
+        // earlier versions of Windows.
+        static ATTRIBUTES: AtomicU32 = AtomicU32::new(c::OBJ_DONT_REPARSE);
+        let object = c::OBJECT_ATTRIBUTES {
+            ObjectName: &name_str,
+            RootDirectory: parent.as_raw_handle(),
+            Attributes: ATTRIBUTES.load(Ordering::Relaxed),
+            ..c::OBJECT_ATTRIBUTES::default()
+        };
+        let status = c::NtOpenFile(
+            &mut handle,
+            access,
+            &object,
+            &mut io_status,
+            c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE,
+            // If `name` is a symlink then open the link rather than the target.
+            c::FILE_OPEN_REPARSE_POINT,
+        );
+        // Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError")
+        if c::nt_success(status) {
+            Ok(File::from_raw_handle(handle))
+        } else if status == c::STATUS_DELETE_PENDING {
+            // We make a special exception for `STATUS_DELETE_PENDING` because
+            // otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is
+            // very unhelpful.
+            Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as _))
+        } else if status == c::STATUS_INVALID_PARAMETER
+            && ATTRIBUTES.load(Ordering::Relaxed) == c::OBJ_DONT_REPARSE
+        {
+            // Try without `OBJ_DONT_REPARSE`. See above.
+            ATTRIBUTES.store(0, Ordering::Relaxed);
+            open_link_no_reparse(parent, name, access)
+        } else {
+            Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as _))
+        }
+    }
 }
 
 impl AsInner<Handle> for File {
@@ -756,30 +968,106 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
     Ok(())
 }
 
+/// Open a file or directory without following symlinks.
+fn open_link(path: &Path, access_mode: u32) -> io::Result<File> {
+    let mut opts = OpenOptions::new();
+    opts.access_mode(access_mode);
+    // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories.
+    // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target.
+    opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
+    File::open(path, &opts)
+}
+
 pub fn remove_dir_all(path: &Path) -> io::Result<()> {
-    let filetype = lstat(path)?.file_type();
-    if filetype.is_symlink() {
-        // On Windows symlinks to files and directories are removed differently.
-        // rmdir only deletes dir symlinks and junctions, not file symlinks.
-        rmdir(path)
+    let file = open_link(path, c::DELETE | c::FILE_LIST_DIRECTORY)?;
+
+    // Test if the file is not a directory or a symlink to a directory.
+    if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 {
+        return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _));
+    }
+    let mut delete: fn(&File) -> io::Result<()> = File::posix_delete;
+    let result = match delete(&file) {
+        Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {
+            match remove_dir_all_recursive(&file, delete) {
+                // Return unexpected errors.
+                Err(e) if e.kind() != io::ErrorKind::DirectoryNotEmpty => return Err(e),
+                result => result,
+            }
+        }
+        // If POSIX delete is not supported for this filesystem then fallback to win32 delete.
+        Err(e)
+            if e.raw_os_error() == Some(c::ERROR_NOT_SUPPORTED as i32)
+                || e.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) =>
+        {
+            delete = File::win32_delete;
+            Err(e)
+        }
+        result => result,
+    };
+    if result.is_ok() {
+        Ok(())
     } else {
-        remove_dir_all_recursive(path)
+        // This is a fallback to make sure the directory is actually deleted.
+        // Otherwise this function is prone to failing with `DirectoryNotEmpty`
+        // due to possible delays between marking a file for deletion and the
+        // file actually being deleted from the filesystem.
+        //
+        // So we retry a few times before giving up.
+        for _ in 0..5 {
+            match remove_dir_all_recursive(&file, delete) {
+                Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {}
+                result => return result,
+            }
+        }
+        // Try one last time.
+        delete(&file)
     }
 }
 
-fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
-    for child in readdir(path)? {
-        let child = child?;
-        let child_type = child.file_type()?;
-        if child_type.is_dir() {
-            remove_dir_all_recursive(&child.path())?;
-        } else if child_type.is_symlink_dir() {
-            rmdir(&child.path())?;
-        } else {
-            unlink(&child.path())?;
+fn remove_dir_all_recursive(f: &File, delete: fn(&File) -> io::Result<()>) -> io::Result<()> {
+    let mut buffer = DirBuff::new();
+    let mut restart = true;
+    // Fill the buffer and iterate the entries.
+    while f.fill_dir_buff(&mut buffer, restart)? {
+        for name in buffer.iter() {
+            // Open the file without following symlinks and try deleting it.
+            // We try opening will all needed permissions and if that is denied
+            // fallback to opening without `FILE_LIST_DIRECTORY` permission.
+            // Note `SYNCHRONIZE` permission is needed for synchronous access.
+            let mut result =
+                open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY);
+            if matches!(&result, Err(e) if e.kind() == io::ErrorKind::PermissionDenied) {
+                result = open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE);
+            }
+            match result {
+                Ok(file) => match delete(&file) {
+                    Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {
+                        // Iterate the directory's files.
+                        // Ignore `DirectoryNotEmpty` errors here. They will be
+                        // caught when `remove_dir_all` tries to delete the top
+                        // level directory. It can then decide if to retry or not.
+                        match remove_dir_all_recursive(&file, delete) {
+                            Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {}
+                            result => result?,
+                        }
+                    }
+                    result => result?,
+                },
+                // Ignore error if a delete is already in progress or the file
+                // has already been deleted. It also ignores sharing violations
+                // (where a file is locked by another process) as these are
+                // usually temporary.
+                Err(e)
+                    if e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _)
+                        || e.kind() == io::ErrorKind::NotFound
+                        || e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {}
+                Err(e) => return Err(e),
+            }
         }
+        // Continue reading directory entries without restarting from the beginning,
+        restart = false;
     }
-    rmdir(path)
+    delete(&f)
 }
 
 pub fn readlink(path: &Path) -> io::Result<PathBuf> {
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index d5e8f12414f..dc581a0675b 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -150,16 +150,18 @@ pub enum RustBacktrace {
     RuntimeDisabled,
 }
 
+// If the `backtrace` feature of this crate isn't enabled quickly return
+// `Disabled` so this can be constant propagated all over the place to
+// optimize away callers.
+#[cfg(not(feature = "backtrace"))]
+pub fn rust_backtrace_env() -> RustBacktrace {
+    RustBacktrace::Disabled
+}
+
 // For now logging is turned off by default, and this function checks to see
 // whether the magical environment variable is present to see if it's turned on.
+#[cfg(feature = "backtrace")]
 pub fn rust_backtrace_env() -> RustBacktrace {
-    // If the `backtrace` feature of this crate isn't enabled quickly return
-    // `None` so this can be constant propagated all over the place to turn
-    // optimize away callers.
-    if !cfg!(feature = "backtrace") {
-        return RustBacktrace::Disabled;
-    }
-
     // Setting environment variables for Fuchsia components isn't a standard
     // or easily supported workflow. For now, always display backtraces.
     if cfg!(target_os = "fuchsia") {
@@ -189,6 +191,15 @@ pub fn rust_backtrace_env() -> RustBacktrace {
     format
 }
 
+/// Setting for printing the full backtrace, unless backtraces are completely disabled
+pub(crate) fn rust_backtrace_print_full() -> RustBacktrace {
+    if cfg!(feature = "backtrace") {
+        RustBacktrace::Print(PrintFmt::Full)
+    } else {
+        RustBacktrace::Disabled
+    }
+}
+
 /// Prints the filename of the backtrace frame.
 ///
 /// See also `output`.
diff --git a/library/stdarch b/library/stdarch
-Subproject 2adc17a5442614dbe34626fdd9b32de7c07b808
+Subproject 11c98f6eb9c4ba48b2362ad4960343b312d056b
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 7c36bb264c4..6d7ab15326c 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -863,7 +863,7 @@ class RustBuild(object):
         >>> rb.get_toml("key2")
         'value2'
 
-        If the key does not exists, the result is None:
+        If the key does not exist, the result is None:
 
         >>> rb.get_toml("key3") is None
         True
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 7bffc1c1520..06ca3ce21b3 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -55,8 +55,8 @@ class ProgramOutOfDate(unittest.TestCase):
     def tearDown(self):
         rmtree(self.container)
 
-    def test_stamp_path_does_not_exists(self):
-        """Return True when the stamp file does not exists"""
+    def test_stamp_path_does_not_exist(self):
+        """Return True when the stamp file does not exist"""
         if os.path.exists(self.rustc_stamp_path):
             os.unlink(self.rustc_stamp_path)
         self.assertTrue(self.build.program_out_of_date(self.rustc_stamp_path, self.key))
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 043b38ecece..e17de0ba49e 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -227,8 +227,10 @@ fn copy_self_contained_objects(
             target_deps.push((target, DependencyType::TargetSelfContained));
         }
 
-        let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);
-        target_deps.push((libunwind_path, DependencyType::TargetSelfContained));
+        if !target.starts_with("s390x") {
+            let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);
+            target_deps.push((libunwind_path, DependencyType::TargetSelfContained));
+        }
     } else if target.ends_with("-wasi") {
         let srcdir = builder
             .wasi_root(target)
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 7d9b3da48ec..a46a4e63714 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1483,11 +1483,10 @@ impl Step for Extended {
             };
             prepare("rustc");
             prepare("cargo");
-            prepare("rust-docs");
             prepare("rust-std");
             prepare("rust-analysis");
             prepare("clippy");
-            for tool in &["rust-demangler", "rls", "rust-analyzer", "miri"] {
+            for tool in &["rust-docs", "rust-demangler", "rls", "rust-analyzer", "miri"] {
                 if built_tools.contains(tool) {
                     prepare(tool);
                 }
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index ac5d5822bfb..cc282fc2f0e 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-backported-commits.sh
         <<: *step
 
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        <<: *step
+
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
@@ -496,6 +500,7 @@ jobs:
                 --enable-full-tools
                 --enable-sanitizers
                 --enable-profiler
+                --disable-docs
                 --set rust.jemalloc
                 --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
diff --git a/src/ci/scripts/verify-stable-version-number.sh b/src/ci/scripts/verify-stable-version-number.sh
new file mode 100755
index 00000000000..82eb3833ccf
--- /dev/null
+++ b/src/ci/scripts/verify-stable-version-number.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# On the stable channel, check whether we're trying to build artifacts with the
+# same version number of a release that's already been published, and fail the
+# build if that's the case.
+#
+# It's a mistake whenever that happens: the release process won't start if it
+# detects a duplicate version number, and the artifacts would have to be
+# rebuilt anyway.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+if [[ "$(cat src/ci/channel)" != "stable" ]]; then
+    echo "This script only works on the stable channel. Skipping the check."
+    exit 0
+fi
+
+version="$(cat src/version)"
+url="https://static.rust-lang.org/dist/channel-rust-${version}.toml"
+
+if curl --silent --fail "${url}" >/dev/null; then
+    echo "The version number ${version} matches an existing release."
+    echo
+    echo "If you're trying to prepare a point release, remember to change the"
+    echo "version number in the src/version file."
+    exit 1
+else
+    echo "The version number ${version} does not match any released version!"
+    exit 0
+fi
diff --git a/src/doc/book b/src/doc/book
-Subproject d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3
+Subproject f17df27fc14696912c48b8b7a7a8fa49e648088
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject c05c452b36358821bf4122f9c418674edd1d713
+Subproject 66d097d3d80e8f88c288c6879c7c2b909ecf8ad
diff --git a/src/doc/reference b/src/doc/reference
-Subproject f8ba2f12df60ee19b96de24ae5b73af3de8a446
+Subproject 4dee6eb63d728ffb9e7a2ed443e9ada9275c69d
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 875464457c4104686faf667f47848aa7b0f0a74
+Subproject 78dd6a4684cf8d6b72275fab6d0429ea40b6633
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 69a0304d41d..53f7108aca3 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -13,6 +13,7 @@
 - [JSON Output](json.md)
 - [Tests](tests/index.md)
 - [Platform Support](platform-support.md)
+    - [Template for target-specific documentation](platform-support/TEMPLATE.md)
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 7f482f0f2b1..11925ab9785 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -170,6 +170,12 @@ The valid types of print values are:
   include a diagnostic note that indicates the linker flags to use when
   linking the resulting static library. The note starts with the text
   `native-static-libs:` to make it easier to fetch the output.
+- `link-args` — This flag does not disable the `--emit` step. When linking,
+  this flag causes `rustc` to print the full linker invocation in a
+  human-readable form. This can be useful when debugging linker options. The
+  exact format of this debugging output is not a stable guarantee, other than
+  that it will include the linker executable and the text of each command-line
+  argument passed to the linker.
 
 [conditional compilation]: ../reference/conditional-compilation.html
 
diff --git a/src/doc/rustc/src/platform-support/TEMPLATE.md b/src/doc/rustc/src/platform-support/TEMPLATE.md
new file mode 100644
index 00000000000..e64783fcf19
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/TEMPLATE.md
@@ -0,0 +1,52 @@
+# `target-name-here`
+
+**Tier: 3**
+
+One-sentence description of the target (e.g. CPU, OS)
+
+## Target maintainers
+
+- Some Person, `email@example.org`, https://github.com/...
+
+## Requirements
+
+Does the target support host tools, or only cross-compilation? Does the target
+support std, or alloc (either with a default allocator, or if the user supplies
+an allocator)?
+
+Document the expectations of binaries built for the target. Do they assume
+specific minimum features beyond the baseline of the CPU/environment/etc? What
+version of the OS or environment do they expect?
+
+Are there notable `#[target_feature(...)]` or `-C target-feature=` values that
+programs may wish to use?
+
+What calling convention does `extern "C"` use on the target?
+
+What format do binaries use by default? ELF, PE, something else?
+
+## Building the target
+
+If Rust doesn't build the target by default, how can users build it? Can users
+just add it to the `target` list in `config.toml`?
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Does the target support running binaries, or do binaries have varying
+expectations that prevent having a standard way to run them? If users can run
+binaries, can they do so in some common emulator, or do they need native
+hardware? Does the target support running the Rust testsuite?
+
+## Cross-compilation toolchains and C code
+
+Does the target support C code? If so, what toolchain target should users use
+to build compatible C code? (This may match the target triple, or it may be a
+toolchain for a different target triple, potentially with specific options or
+caveats.)
diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md
index cc02b294b44..53d0470fa81 100644
--- a/src/doc/rustc/src/target-tier-policy.md
+++ b/src/doc/rustc/src/target-tier-policy.md
@@ -62,13 +62,22 @@ not preclude an existing target's maintainers using issues (on the Rust
 repository or otherwise) to track requirements that have not yet been met, as
 appropriate; however, before officially proposing the introduction or promotion
 of a target, it should meet all of the necessary requirements. A target
-proposal is encouraged to quote the corresponding requirements verbatim as part
-of explaining how the target meets those requirements.
+proposal must quote the corresponding requirements verbatim and respond to them
+as part of explaining how the target meets those requirements. (For the
+requirements that simply state that the target or the target developers must
+not do something, it suffices to acknowledge the requirement.)
 
 For a list of all supported targets and their corresponding tiers ("tier 3",
 "tier 2", "tier 2 with host tools", "tier 1", or "tier 1 with host tools"), see
 [platform support](platform-support.md).
 
+Several parts of this policy require providing target-specific documentation.
+Such documentation should typically appear in a subdirectory of the
+platform-support section of this rustc manual, with a link from the target's
+entry in [platform support](platform-support.md). Use
+[TEMPLATE.md](platform-support/TEMPLATE.md) as a base, and see other
+documentation in that directory for examples.
+
 Note that a target must have already received approval for the next lower tier,
 and spent a reasonable amount of time at that tier, before making a proposal
 for promotion to the next higher tier; this is true even if a target meets the
@@ -139,17 +148,19 @@ approved by the appropriate team for that shared code before acceptance.
     or binary. In other words, the introduction of the target must not cause a
     user installing or running a version of Rust or the Rust tools to be
     subject to any new license requirements.
-  - If the target supports building host tools (such as `rustc` or `cargo`),
-    those host tools must not depend on proprietary (non-FOSS) libraries, other
-    than ordinary runtime libraries supplied by the platform and commonly used
-    by other binaries built for the target. For instance, `rustc` built for the
-    target may depend on a common proprietary C runtime library or console
-    output library, but must not depend on a proprietary code generation
-    library or code optimization library. Rust's license permits such
-    combinations, but the Rust project has no interest in maintaining such
-    combinations within the scope of Rust itself, even at tier 3.
-  - Targets should not require proprietary (non-FOSS) components to link a
-    functional binary or library.
+  - Compiling, linking, and emitting functional binaries, libraries, or other
+    code for the target (whether hosted on the target itself or cross-compiling
+    from another target) must not depend on proprietary (non-FOSS) libraries.
+    Host tools built for the target itself may depend on the ordinary runtime
+    libraries supplied by the platform and commonly used by other applications
+    built for the target, but those libraries must not be required for code
+    generation for the target; cross-compilation to the target must not require
+    such libraries at all. For instance, `rustc` built for the target may
+    depend on a common proprietary C runtime library or console output library,
+    but must not depend on a proprietary code generation library or code
+    optimization library. Rust's license permits such combinations, but the
+    Rust project has no interest in maintaining such combinations within the
+    scope of Rust itself, even at tier 3.
   - "onerous" here is an intentionally subjective term. At a minimum, "onerous"
     legal/licensing terms include but are *not* limited to: non-disclosure
     requirements, non-compete requirements, contributor license agreements
@@ -184,9 +195,9 @@ approved by the appropriate team for that shared code before acceptance.
   target not implementing those portions.
 - The target must provide documentation for the Rust community explaining how
   to build for the target, using cross-compilation if possible. If the target
-  supports running tests (even if they do not pass), the documentation must
-  explain how to run tests for the target, using emulation if possible or
-  dedicated hardware if necessary.
+  supports running binaries, or running tests (even if they do not pass), the
+  documentation must explain how to run such binaries or tests for the target,
+  using emulation if possible or dedicated hardware if necessary.
 - Tier 3 targets must not impose burden on the authors of pull requests, or
   other developers in the community, to maintain the target. In particular,
   do not post comments (automated or manual) on a PR that derail or suggest a
diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py
index 7ed317c778f..de1717b3f3f 100644
--- a/src/etc/check_missing_items.py
+++ b/src/etc/check_missing_items.py
@@ -83,7 +83,9 @@ def check_type(ty):
                         check_type(arg["const"]["type"])
                 for binding in args["angle_bracketed"]["bindings"]:
                     if "equality" in binding["binding"]:
-                        check_type(binding["binding"]["equality"])
+                        term = binding["binding"]["equality"]
+                        if "type" in term: check_type(term["type"])
+                        elif "const" in term: check_type(term["const"])
                     elif "constraint" in binding["binding"]:
                         for bound in binding["binding"]["constraint"]:
                             check_generic_bound(bound)
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 48a341ffe08..6bb235b2c83 100644
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -401,7 +401,7 @@ def get_tree_count(tree, path):
     return len(tree.findall(path))
 
 
-def check_snapshot(snapshot_name, tree):
+def check_snapshot(snapshot_name, tree, normalize_to_text):
     assert rust_test_path.endswith('.rs')
     snapshot_path = '{}.{}.{}'.format(rust_test_path[:-3], snapshot_name, 'html')
     try:
@@ -413,7 +413,10 @@ def check_snapshot(snapshot_name, tree):
         else:
             raise FailedCheck('No saved snapshot value')
 
-    actual_str = ET.tostring(tree).decode('utf-8')
+    if not normalize_to_text:
+        actual_str = ET.tostring(tree).decode('utf-8')
+    else:
+        actual_str = flatten(tree)
 
     if expected_str != actual_str:
         if bless:
@@ -494,11 +497,16 @@ def check_command(c, cache):
                 [snapshot_name, html_path, pattern] = c.args
                 tree = cache.get_tree(html_path)
                 xpath = normalize_xpath(pattern)
+                normalize_to_text = False
+                if xpath.endswith('/text()'):
+                    xpath = xpath[:-7]
+                    normalize_to_text = True
+
                 subtrees = tree.findall(xpath)
                 if len(subtrees) == 1:
                     [subtree] = subtrees
                     try:
-                        check_snapshot(snapshot_name, subtree)
+                        check_snapshot(snapshot_name, subtree, normalize_to_text)
                         ret = True
                     except FailedCheck as err:
                         cerr = str(err)
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index ccb844cd10b..67d167e86df 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -8,7 +8,7 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
-askama = { version = "0.11", default-features = false }
+askama = { version = "0.11", default-features = false, features = ["config"] }
 atty = "0.2"
 pulldown-cmark = { version = "0.9", default-features = false }
 minifier = "0.0.41"
diff --git a/src/librustdoc/askama.toml b/src/librustdoc/askama.toml
new file mode 100644
index 00000000000..0c984f637ba
--- /dev/null
+++ b/src/librustdoc/askama.toml
@@ -0,0 +1,2 @@
+[general]
+dirs = ["html/templates"]
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 09692d27e8f..18a4d8a4753 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -553,8 +553,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                             if self.is_fn_trait(trait_) && left_name == sym::Output {
                                 ty_to_fn
                                     .entry(*ty.clone())
-                                    .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone())))
-                                    .or_insert((None, Some(rhs)));
+                                    .and_modify(|e| {
+                                        *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
+                                    })
+                                    .or_insert((None, Some(rhs.ty().unwrap().clone())));
                                 continue;
                             }
 
@@ -570,7 +572,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                                 GenericArgs::AngleBracketed { ref mut bindings, .. } => {
                                     bindings.push(TypeBinding {
                                         name: left_name,
-                                        kind: TypeBindingKind::Equality { ty: rhs },
+                                        kind: TypeBindingKind::Equality { term: rhs },
                                     });
                                 }
                                 GenericArgs::Parenthesized { .. } => {
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index dfee2b702c1..b72d2624177 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -8,6 +8,7 @@ use std::mem;
 use std::ops;
 
 use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::Features;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{sym, Symbol};
@@ -43,23 +44,22 @@ crate struct InvalidCfgError {
 
 impl Cfg {
     /// Parses a `NestedMetaItem` into a `Cfg`.
-    fn parse_nested(nested_cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
+    fn parse_nested(
+        nested_cfg: &NestedMetaItem,
+        exclude: &FxHashSet<Cfg>,
+    ) -> Result<Option<Cfg>, InvalidCfgError> {
         match nested_cfg {
-            NestedMetaItem::MetaItem(ref cfg) => Cfg::parse(cfg),
+            NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
             NestedMetaItem::Literal(ref lit) => {
                 Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
             }
         }
     }
 
-    /// Parses a `MetaItem` into a `Cfg`.
-    ///
-    /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or
-    /// `target_os = "redox"`.
-    ///
-    /// If the content is not properly formatted, it will return an error indicating what and where
-    /// the error is.
-    crate fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
+    crate fn parse_without(
+        cfg: &MetaItem,
+        exclude: &FxHashSet<Cfg>,
+    ) -> Result<Option<Cfg>, InvalidCfgError> {
         let name = match cfg.ident() {
             Some(ident) => ident.name,
             None => {
@@ -70,9 +70,15 @@ impl Cfg {
             }
         };
         match cfg.kind {
-            MetaItemKind::Word => Ok(Cfg::Cfg(name, None)),
+            MetaItemKind::Word => {
+                let cfg = Cfg::Cfg(name, None);
+                if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) }
+            }
             MetaItemKind::NameValue(ref lit) => match lit.kind {
-                LitKind::Str(value, _) => Ok(Cfg::Cfg(name, Some(value))),
+                LitKind::Str(value, _) => {
+                    let cfg = Cfg::Cfg(name, Some(value));
+                    if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) }
+                }
                 _ => Err(InvalidCfgError {
                     // FIXME: if the main #[cfg] syntax decided to support non-string literals,
                     // this should be changed as well.
@@ -81,23 +87,40 @@ impl Cfg {
                 }),
             },
             MetaItemKind::List(ref items) => {
-                let mut sub_cfgs = items.iter().map(Cfg::parse_nested);
-                match name {
+                let sub_cfgs =
+                    items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose());
+                let ret = match name {
                     sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)),
                     sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)),
                     sym::not => {
+                        let mut sub_cfgs = sub_cfgs.collect::<Vec<_>>();
                         if sub_cfgs.len() == 1 {
-                            Ok(!sub_cfgs.next().unwrap()?)
+                            Ok(!sub_cfgs.pop().unwrap()?)
                         } else {
                             Err(InvalidCfgError { msg: "expected 1 cfg-pattern", span: cfg.span })
                         }
                     }
                     _ => Err(InvalidCfgError { msg: "invalid predicate", span: cfg.span }),
+                };
+                match ret {
+                    Ok(c) => Ok(Some(c)),
+                    Err(e) => Err(e),
                 }
             }
         }
     }
 
+    /// Parses a `MetaItem` into a `Cfg`.
+    ///
+    /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or
+    /// `target_os = "redox"`.
+    ///
+    /// If the content is not properly formatted, it will return an error indicating what and where
+    /// the error is.
+    crate fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
+        Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
+    }
+
     /// Checks whether the given configuration can be matched in the current session.
     ///
     /// Equivalent to `attr::cfg_matches`.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a5bc70a74ae..e759baa0458 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -272,9 +272,10 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
                 bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
             },
 
-            hir::WherePredicate::EqPredicate(ref wrp) => {
-                WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) }
-            }
+            hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
+                lhs: wrp.lhs_ty.clean(cx),
+                rhs: wrp.rhs_ty.clean(cx).into(),
+            },
         }
     }
 }
@@ -352,10 +353,31 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
     }
 }
 
+impl<'tcx> Clean<Term> for ty::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+        match self {
+            ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            ty::Term::Const(c) => Term::Constant(c.clean(cx)),
+        }
+    }
+}
+
+impl<'tcx> Clean<Term> for hir::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+        match self {
+            hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            hir::Term::Const(c) => {
+                let def_id = cx.tcx.hir().local_def_id(c.hir_id);
+                Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
+            }
+        }
+    }
+}
+
 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
-        let ty::ProjectionPredicate { projection_ty, ty } = self;
-        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
+        let ty::ProjectionPredicate { projection_ty, term } = self;
+        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
     }
 }
 
@@ -613,7 +635,7 @@ fn clean_ty_generics(
 
             if let Some(param_idx) = param_idx {
                 if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
-                    let p = p.clean(cx)?;
+                    let p: WherePredicate = p.clean(cx)?;
 
                     b.extend(
                         p.get_bounds()
@@ -624,11 +646,16 @@ fn clean_ty_generics(
                     );
 
                     let proj = projection
-                        .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
+                        .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
                     if let Some(((_, trait_did, name), rhs)) =
                         proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
                     {
-                        impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
+                        // FIXME(...): Remove this unwrap()
+                        impl_trait_proj.entry(param_idx).or_default().push((
+                            trait_did,
+                            name,
+                            rhs.ty().unwrap(),
+                        ));
                     }
 
                     return None;
@@ -647,7 +674,7 @@ fn clean_ty_generics(
             if let Some(proj) = impl_trait_proj.remove(&idx) {
                 for (trait_did, name, rhs) in proj {
                     let rhs = rhs.clean(cx);
-                    simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+                    simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
                 }
             }
         } else {
@@ -1495,7 +1522,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 for pb in obj.projection_bounds() {
                     bindings.push(TypeBinding {
                         name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
-                        kind: TypeBindingKind::Equality { ty: pb.skip_binder().ty.clean(cx) },
+                        kind: TypeBindingKind::Equality {
+                            term: pb.skip_binder().term.clean(cx).into(),
+                        },
                     });
                 }
 
@@ -1566,7 +1595,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                                                 .ident
                                                 .name,
                                             kind: TypeBindingKind::Equality {
-                                                ty: proj.ty.clean(cx),
+                                                term: proj.term.clean(cx),
                                             },
                                         })
                                     } else {
@@ -2114,10 +2143,10 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
 impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
         match *self {
-            hir::TypeBindingKind::Equality { ref ty } => {
-                TypeBindingKind::Equality { ty: ty.clean(cx) }
+            hir::TypeBindingKind::Equality { ref term } => {
+                TypeBindingKind::Equality { term: term.clean(cx) }
             }
-            hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
+            hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
                 bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
             },
         }
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 4c81e75e8d6..0bad1532808 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -92,7 +92,7 @@ crate fn merge_bounds(
     bounds: &mut Vec<clean::GenericBound>,
     trait_did: DefId,
     name: Symbol,
-    rhs: &clean::Type,
+    rhs: &clean::Term,
 ) -> bool {
     !bounds.iter_mut().any(|b| {
         let trait_ref = match *b {
@@ -110,14 +110,14 @@ crate fn merge_bounds(
             PP::AngleBracketed { ref mut bindings, .. } => {
                 bindings.push(clean::TypeBinding {
                     name,
-                    kind: clean::TypeBindingKind::Equality { ty: rhs.clone() },
+                    kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
                 });
             }
             PP::Parenthesized { ref mut output, .. } => match output {
-                Some(o) => assert_eq!(o.as_ref(), rhs),
+                Some(o) => assert_eq!(&clean::Term::Type(o.as_ref().clone()), rhs),
                 None => {
-                    if *rhs != clean::Type::Tuple(Vec::new()) {
-                        *output = Some(Box::new(rhs.clone()));
+                    if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
+                        *output = Some(Box::new(rhs.ty().unwrap().clone()));
                     }
                 }
             },
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 00c6e38839f..993503005d7 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -831,8 +831,9 @@ impl AttributesExt for [ast::Attribute] {
                 self.iter()
                     .filter(|attr| attr.has_name(sym::cfg))
                     .filter_map(|attr| single(attr.meta_item_list()?))
-                    .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
-                    .filter(|cfg| !hidden_cfg.contains(cfg))
+                    .filter_map(|attr| {
+                        Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()
+                    })
                     .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
             } else {
                 Cfg::True
@@ -1040,9 +1041,9 @@ impl Attributes {
     ) -> Attributes {
         let mut doc_strings: Vec<DocFragment> = vec![];
         let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
-            if let Some(value) = attr.doc_str() {
+            if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
                 trace!("got doc_str={:?}", value);
-                let value = beautify_doc_string(value);
+                let value = beautify_doc_string(value, kind);
                 let kind = if attr.is_doc_comment() {
                     DocFragmentKind::SugaredDoc
                 } else {
@@ -1212,7 +1213,7 @@ impl Lifetime {
 crate enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: Type, rhs: Type },
+    EqPredicate { lhs: Type, rhs: Term },
 }
 
 impl WherePredicate {
@@ -1308,7 +1309,9 @@ impl FnDecl {
             FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
                 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
                     let bindings = trait_.bindings().unwrap();
-                    FnRetTy::Return(bindings[0].ty().clone())
+                    let ret_ty = bindings[0].term();
+                    let ty = ret_ty.ty().expect("Unexpected constant return term");
+                    FnRetTy::Return(ty.clone())
                 }
                 _ => panic!("unexpected desugaring of async function"),
             },
@@ -2122,6 +2125,24 @@ crate struct Constant {
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
+crate enum Term {
+    Type(Type),
+    Constant(Constant),
+}
+
+impl Term {
+    crate fn ty(&self) -> Option<&Type> {
+        if let Term::Type(ty) = self { Some(ty) } else { None }
+    }
+}
+
+impl From<Type> for Term {
+    fn from(ty: Type) -> Self {
+        Term::Type(ty)
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 crate enum ConstantKind {
     /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
     /// `BodyId`, we need to handle it on its own.
@@ -2283,14 +2304,14 @@ crate struct TypeBinding {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 crate enum TypeBindingKind {
-    Equality { ty: Type },
+    Equality { term: Term },
     Constraint { bounds: Vec<GenericBound> },
 }
 
 impl TypeBinding {
-    crate fn ty(&self) -> &Type {
+    crate fn term(&self) -> &Term {
         match self.kind {
-            TypeBindingKind::Equality { ref ty } => ty,
+            TypeBindingKind::Equality { ref term } => term,
             _ => panic!("expected equality type binding for parenthesized generic args"),
         }
     }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index c7c049f9914..3b926e44403 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -492,9 +492,9 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
                 "could not resolve path `{}`",
                 path.segments
                     .iter()
-                    .map(|segment| segment.ident.as_str().to_string())
-                    .collect::<Vec<_>>()
-                    .join("::")
+                    .map(|segment| segment.ident.as_str())
+                    .intersperse("::")
+                    .collect::<String>()
             );
             let mut err = rustc_errors::struct_span_err!(
                 self.tcx.sess,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8571a6a137f..08840626259 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1442,11 +1442,11 @@ impl clean::TypeBinding {
         display_fn(move |f| {
             f.write_str(self.name.as_str())?;
             match self.kind {
-                clean::TypeBindingKind::Equality { ref ty } => {
+                clean::TypeBindingKind::Equality { ref term } => {
                     if f.alternate() {
-                        write!(f, " = {:#}", ty.print(cx))?;
+                        write!(f, " = {:#}", term.print(cx))?;
                     } else {
-                        write!(f, " = {}", ty.print(cx))?;
+                        write!(f, " = {}", term.print(cx))?;
                     }
                 }
                 clean::TypeBindingKind::Constraint { ref bounds } => {
@@ -1492,6 +1492,18 @@ impl clean::GenericArg {
     }
 }
 
+impl clean::types::Term {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cx: &'a Context<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+        match self {
+            clean::types::Term::Type(ty) => ty.print(cx),
+            _ => todo!(),
+        }
+    }
+}
+
 crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
     struct WithFormatter<F>(Cell<Option<F>>);
 
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 3fd9c0a1944..a9a3a0af276 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -923,9 +923,7 @@ impl LangString {
 
         data.original = string.to_owned();
 
-        let tokens = Self::tokens(string).collect::<Vec<&str>>();
-
-        for token in tokens {
+        for token in Self::tokens(string) {
             match token {
                 "should_panic" => {
                     data.should_panic = true;
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 865e14f694d..2455d56bd2b 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -554,16 +554,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             extra_scripts: &[],
             static_extra_scripts: &[],
         };
-        let sidebar = if let Some(ref version) = self.shared.cache.crate_version {
-            format!(
-                "<h2 class=\"location\">Crate {}</h2>\
-                     <div class=\"block version\">\
-                         <p>Version {}</p>\
-                     </div>\
-                     <a id=\"all-types\" href=\"index.html\"><p>Back to index</p></a>",
-                crate_name,
-                Escape(version),
-            )
+        let sidebar = if self.shared.cache.crate_version.is_some() {
+            format!("<h2 class=\"location\">Crate {}</h2>", crate_name)
         } else {
             String::new()
         };
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 7f3e5d15de1..8badce8226f 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -423,6 +423,12 @@ fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<S
             vec![
                 Setting::from(("use-system-theme", "Use system theme", true)),
                 Setting::Select {
+                    js_data_name: "theme",
+                    description: "Theme",
+                    default_value: "light",
+                    options: theme_names.clone(),
+                },
+                Setting::Select {
                     js_data_name: "preferred-dark-theme",
                     description: "Preferred dark theme",
                     default_value: "dark",
@@ -793,6 +799,20 @@ fn assoc_type(
     }
 }
 
+/// Writes a span containing the versions at which an item became stable and/or const-stable. For
+/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
+/// write a span containing "1.0.0 (const: 1.45.0)".
+///
+/// Returns `true` if a stability annotation was rendered.
+///
+/// Stability and const-stability are considered separately. If the item is unstable, no version
+/// will be written. If the item is const-unstable, "const: unstable" will be appended to the
+/// span, with a link to the tracking issue if present. If an item's stability or const-stability
+/// version matches the version of its enclosing item, that version will be omitted.
+///
+/// Note that it is possible for an unstable function to be const-stable. In that case, the span
+/// will include the const-stable version, but no stable version will be emitted, as a natural
+/// consequence of the above rules.
 fn render_stability_since_raw(
     w: &mut Buffer,
     ver: Option<Symbol>,
@@ -800,51 +820,56 @@ fn render_stability_since_raw(
     containing_ver: Option<Symbol>,
     containing_const_ver: Option<Symbol>,
 ) -> bool {
-    let ver = ver.filter(|inner| !inner.is_empty());
+    let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
 
-    match (ver, const_stability) {
-        // stable and const stable
-        (Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. }))
+    let mut title = String::new();
+    let mut stability = String::new();
+
+    if let Some(ver) = stable_version {
+        stability.push_str(&ver.as_str());
+        title.push_str(&format!("Stable since Rust version {}", ver));
+    }
+
+    let const_title_and_stability = match const_stability {
+        Some(ConstStability { level: StabilityLevel::Stable { since }, .. })
             if Some(since) != containing_const_ver =>
         {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
-                v, since
-            );
+            Some((format!("const since {}", since), format!("const: {}", since)))
         }
-        // stable and const unstable
-        (
-            Some(v),
-            Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }),
-        ) => {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}, const unstable\">{0} (const: ",
-                v
-            );
-            if let Some(n) = issue {
-                write!(
-                    w,
-                    "<a href=\"https://github.com/rust-lang/rust/issues/{}\" title=\"Tracking issue for {}\">unstable</a>",
+        Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
+            let unstable = if let Some(n) = issue {
+                format!(
+                    r#"<a href="https://github.com/rust-lang/rust/issues/{}" title="Tracking issue for {}">unstable</a>"#,
                     n, feature
-                );
+                )
             } else {
-                write!(w, "unstable");
-            }
-            write!(w, ")</span>");
+                String::from("unstable")
+            };
+
+            Some((String::from("const unstable"), format!("const: {}", unstable)))
         }
-        // stable
-        (Some(v), _) if ver != containing_ver => {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
-                v
-            );
+        _ => None,
+    };
+
+    if let Some((const_title, const_stability)) = const_title_and_stability {
+        if !title.is_empty() {
+            title.push_str(&format!(", {}", const_title));
+        } else {
+            title.push_str(&const_title);
+        }
+
+        if !stability.is_empty() {
+            stability.push_str(&format!(" ({})", const_stability));
+        } else {
+            stability.push_str(&const_stability);
         }
-        _ => return false,
     }
-    true
+
+    if !stability.is_empty() {
+        write!(w, r#"<span class="since" title="{}">{}</span>"#, title, stability);
+    }
+
+    !stability.is_empty()
 }
 
 fn render_assoc_item(
@@ -1738,13 +1763,6 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
             buffer,
             "<h2 class=\"location\"><a href=\"#\">{}{}</a></h2>",
             match *it.kind {
-                clean::StructItem(..) => "Struct ",
-                clean::TraitItem(..) => "Trait ",
-                clean::PrimitiveItem(..) => "Primitive Type ",
-                clean::UnionItem(..) => "Union ",
-                clean::EnumItem(..) => "Enum ",
-                clean::TypedefItem(..) => "Type Definition ",
-                clean::ForeignTypeItem => "Foreign Type ",
                 clean::ModuleItem(..) =>
                     if it.is_crate() {
                         "Crate "
@@ -1757,26 +1775,14 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         );
     }
 
+    buffer.write_str("<div class=\"sidebar-elems\">");
     if it.is_crate() {
+        write!(buffer, "<div class=\"block\"><ul>");
         if let Some(ref version) = cx.cache().crate_version {
-            write!(
-                buffer,
-                "<div class=\"block version\">\
-                     <div class=\"narrow-helper\"></div>\
-                     <p>Version {}</p>\
-                 </div>",
-                Escape(version),
-            );
+            write!(buffer, "<li class=\"version\">Version {}</li>", Escape(version));
         }
-    }
-
-    buffer.write_str("<div class=\"sidebar-elems\">");
-    if it.is_crate() {
-        write!(
-            buffer,
-            "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
-            it.name.as_ref().expect("crates always have a name"),
-        );
+        write!(buffer, "<li><a id=\"all-types\" href=\"all.html\">All Items</a></li>");
+        buffer.write_str("</div></ul>");
     }
 
     match *it.kind {
@@ -1800,7 +1806,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     // to navigate the documentation (though slightly inefficiently).
 
     if !it.is_mod() {
-        buffer.write_str("<h2 class=\"location\">Other items in<br>");
+        buffer.write_str("<h2 class=\"location\">In ");
         for (i, name) in cx.current.iter().take(parentlen).enumerate() {
             if i > 0 {
                 buffer.write_str("::<wbr>");
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index d7f33d6131c..bdd8aa430b2 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -111,6 +111,12 @@ body {
 	font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif;
 	margin: 0;
 	position: relative;
+	/* We use overflow-wrap: break-word for Safari, which doesn't recognize
+	   `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */
+	overflow-wrap: break-word;
+	/* Then override it with `anywhere`, which is required to make non-Safari browsers break
+	   more aggressively when we want them to. */
+	overflow-wrap: anywhere;
 
 	-webkit-font-feature-settings: "kern", "liga";
 	-moz-font-feature-settings: "kern", "liga";
@@ -142,13 +148,11 @@ h1.fqn {
 }
 .main-heading {
 	display: flex;
+	flex-wrap: wrap;
+	justify-content: space-between;
 	border-bottom: 1px dashed #DDDDDD;
 	padding-bottom: 6px;
 	margin-bottom: 15px;
-
-	/* workaround to keep flex from breaking below 700 px width due to the float: right on the nav
-	   above the h1 */
-	padding-left: 1px;
 }
 .main-heading a:hover {
 	text-decoration: underline;
@@ -163,8 +167,7 @@ h1.fqn {
 	section hierarchies. */
 h2,
 .top-doc h3,
-.top-doc h4,
-.sidebar .others h3 {
+.top-doc h4 {
 	border-bottom: 1px solid;
 }
 h3.code-header {
@@ -200,7 +203,11 @@ div.impl-items > div {
 }
 
 h1, h2, h3, h4, h5, h6,
-.sidebar, a.source, .search-input, .search-results .result-name,
+.sidebar,
+.mobile-topbar,
+a.source,
+.search-input,
+.search-results .result-name,
 .content table td:first-child > a,
 .item-left > a,
 .out-of-band,
@@ -255,6 +262,11 @@ textarea {
 	margin: 0;
 }
 
+button {
+	/* Buttons on Safari have different default padding than other platforms. Make them the same. */
+	padding: 1px 6px;
+}
+
 /* end tweaks for normalize.css 8 */
 
 .rustdoc {
@@ -353,15 +365,25 @@ nav.sub {
 }
 
 .sidebar {
-	width: 200px;
+	font-size: 0.9rem;
+	width: 250px;
+	min-width: 200px;
 	overflow-y: scroll;
 	position: sticky;
-	min-width: 200px;
 	height: 100vh;
 	top: 0;
 	left: 0;
 }
 
+.sidebar-elems,
+.sidebar > .location {
+	padding-left: 24px;
+}
+
+.sidebar .location {
+	overflow-wrap: anywhere;
+}
+
 .rustdoc.source .sidebar {
 	width: 50px;
 	min-width: 0px;
@@ -390,6 +412,10 @@ nav.sub {
 	visibility: visible;
 }
 
+#all-types {
+	margin-top: 1em;
+}
+
 /* Improve the scrollbar display on firefox */
 * {
 	scrollbar-width: initial;
@@ -409,47 +435,28 @@ nav.sub {
 	-webkit-box-shadow: inset 0;
 }
 
-.sidebar .block > ul > li {
-	margin-right: -10px;
-}
-
 /* Everything else */
 
 .hidden {
 	display: none !important;
 }
 
-.logo-container {
+.sidebar .logo-container {
 	display: flex;
 	margin-top: 10px;
 	margin-bottom: 10px;
 	justify-content: center;
 }
 
+.version {
+	overflow-wrap: break-word;
+}
+
 .logo-container > img {
 	height: 100px;
 	width: 100px;
 }
 
-.sidebar .location {
-	border: 1px solid;
-	font-size: 1.0625rem;
-	margin: 30px 10px 20px 10px;
-	text-align: center;
-	word-wrap: break-word;
-	font-weight: inherit;
-	padding: 0;
-}
-
-.sidebar .version {
-	font-size: 0.9375rem;
-	text-align: center;
-	border-bottom: 1px solid;
-	overflow-wrap: break-word;
-	word-wrap: break-word; /* deprecated */
-	word-break: break-word; /* Chrome, non-standard */
-}
-
 .location:empty {
 	border: none;
 }
@@ -463,48 +470,45 @@ nav.sub {
 
 .block {
 	padding: 0;
-	margin-bottom: 14px;
-}
-.block h2, .block h3 {
-	text-align: center;
 }
 .block ul, .block li {
-	margin: 0 10px;
 	padding: 0;
 	list-style: none;
 }
 
 .block a {
 	display: block;
+	padding: 0.3em;
+	margin-left: -0.3em;
+
 	text-overflow: ellipsis;
 	overflow: hidden;
-	line-height: 15px;
-	padding: 7px 5px;
-	font-size: 0.875rem;
-	font-weight: 300;
-	transition: border 500ms ease-out;
 }
 
-.sidebar-title {
-	border-top: 1px solid;
-	border-bottom: 1px solid;
-	text-align: center;
-	font-size: 1.0625rem;
-	margin-bottom: 5px;
-	font-weight: inherit;
+.sidebar h2 {
+	border-bottom: none;
+	font-weight: 500;
 	padding: 0;
+	margin: 0;
+	margin-top: 1rem;
+	margin-bottom: 1rem;
 }
 
-.sidebar-links {
-	margin-bottom: 15px;
+.sidebar h3 {
+	font-size: 1.1rem;
+	font-weight: 500;
+	padding: 0;
+	margin: 0;
+	margin-top: 0.5rem;
+	margin-bottom: 0.25rem;
 }
 
-.sidebar-links > a {
-	padding-left: 10px;
-	width: 100%;
+.sidebar-links,
+.block {
+	margin-bottom: 2em;
 }
 
-.sidebar-menu {
+.mobile-topbar {
 	display: none;
 }
 
@@ -576,6 +580,7 @@ nav.sub {
 }
 
 .docblock-short {
+	overflow-wrap: break-word;
 	overflow-wrap: anywhere;
 }
 .docblock-short p {
@@ -618,11 +623,7 @@ nav.sub {
 
 .content .out-of-band {
 	flex-grow: 0;
-	text-align: right;
-	margin-left: auto;
-	margin-right: 0;
 	font-size: 1.15rem;
-	padding: 0 0 0 12px;
 	font-weight: normal;
 	float: right;
 }
@@ -641,6 +642,7 @@ nav.sub {
 	flex-grow: 1;
 	margin: 0px;
 	padding: 0px;
+	overflow-wrap: break-word;
 	overflow-wrap: anywhere;
 }
 
@@ -669,6 +671,7 @@ nav.sub {
 	margin: .5em 0;
 	width: calc(100% - 2px);
 	overflow-x: auto;
+	overflow-wrap: normal;
 	display: block;
 }
 
@@ -774,13 +777,11 @@ nav.sub {
 	margin-top: 0;
 }
 
-nav:not(.sidebar) {
+nav.sub {
 	flex-grow: 1;
-	border-bottom: 1px solid;
-	padding-bottom: 10px;
 	margin-bottom: 25px;
 }
-.source nav:not(.sidebar).sub {
+.source nav.sub {
 	margin-left: 32px;
 }
 nav.main {
@@ -934,11 +935,6 @@ h2.small-section-header > .anchor {
 	width: 100%;
 }
 
-#crate-search + .search-input {
-	border-radius: 0 1px 1px 0;
-	width: calc(100% - 32px);
-}
-
 .search-input:focus {
 	border-radius: 2px;
 	border: 0;
@@ -1390,18 +1386,6 @@ pre.rust {
 	margin-left: 5px;
 }
 
-#all-types {
-	text-align: center;
-	border: 1px solid;
-	margin: 0 10px;
-	margin-bottom: 10px;
-	display: block;
-	border-radius: 7px;
-}
-#all-types > p {
-	margin: 5px 0;
-}
-
 #sidebar-toggle {
 	position: sticky;
 	top: 0;
@@ -1495,6 +1479,7 @@ pre.rust {
 	padding: 4px 8px;
 	text-align: center;
 	background: rgba(0,0,0,0);
+	overflow-wrap: normal;
 }
 
 #theme-choices > button:not(:first-child) {
@@ -1746,8 +1731,19 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 }
 
 @media (max-width: 700px) {
-	body {
+	/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
+	   or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured
+	   by the topbar. Anything with an `id` gets scroll-margin-top equal to .mobile-topbar's size.
+	*/
+	*[id] {
+		scroll-margin-top: 45px;
+	}
+
+	.rustdoc {
 		padding-top: 0px;
+		/* Sidebar should overlay main content, rather than pushing main content to the right.
+		   Turn off `display: flex` on the body element. */
+		display: block;
 	}
 
 	main {
@@ -1755,132 +1751,123 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		padding-top: 0px;
 	}
 
-	.rustdoc {
+	.rustdoc,
+	.main-heading {
 		flex-direction: column;
 	}
 
-	.rustdoc:not(.source) > .sidebar {
-		width: 100%;
-		height: 45px;
-		min-height: 40px;
-		max-height: 45px;
-		margin: 0;
-		padding: 0 15px;
-		position: static;
-		z-index: 11;
-		overflow-y: hidden;
+	.content .out-of-band {
+		text-align: left;
+		margin-left: initial;
+		padding: initial;
 	}
 
-	.rustdoc.source > .sidebar {
+	.content .out-of-band .since::before {
+		content: "Since ";
+	}
+
+	#copy-path {
+		display: none;
+	}
+
+	/* Hide the logo and item name from the sidebar. Those are displayed
+	   in the mobile-topbar instead. */
+	.sidebar .sidebar-logo,
+	.sidebar .location {
+		display: none;
+	}
+
+	.sidebar-elems {
+		margin-top: 1em;
+	}
+
+	.sidebar {
 		position: fixed;
-		top: 0;
-		left: 0;
+		top: 45px;
+		/* Hide the sidebar offscreen while not in use. Doing this instead of display: none means
+		   the sidebar stays visible for screen readers, which is useful for navigation. */
+		left: -1000px;
+		margin-left: 0;
+		background-color: rgba(0,0,0,0);
 		margin: 0;
+		padding: 0;
+		padding-left: 15px;
 		z-index: 11;
-		width: 0;
 	}
 
-	.sidebar.mobile {
-		position: sticky !important;
+	/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
+	   so don't bump down the main content or the sidebar. */
+	.source main,
+	.source .sidebar {
 		top: 0;
+		padding: 0;
+	}
+
+	.sidebar.shown,
+	.sidebar.expanded,
+	.sidebar:focus-within {
 		left: 0;
-		width: 100%;
-		margin-left: 0;
-		background-color: rgba(0,0,0,0);
 	}
 
-	.sidebar > .location {
-		float: right;
-		margin: 0px;
-		margin-top: 2px;
-		padding: 3px 10px 1px 10px;
-		min-height: 39px;
-		background: inherit;
-		text-align: left;
-		font-size: 1.5rem;
+	.rustdoc.source > .sidebar {
+		position: fixed;
+		margin: 0;
+		z-index: 11;
+		width: 0;
 	}
 
-	.sidebar .location:empty {
-		padding: 0;
+	.mobile-topbar .location {
+		border: none;
+		margin: 0;
+		margin-left: auto;
+		padding: 0.3em;
+		padding-right: 0.6em;
+		text-overflow: ellipsis;
+		overflow-x: hidden;
 	}
 
-	.rustdoc:not(.source) .sidebar .logo-container {
-		width: 35px;
-		height: 35px;
-		margin-top: 5px;
-		margin-bottom: 5px;
-		float: left;
-		margin-left: 50px;
+	.mobile-topbar .logo-container {
+		max-height: 45px;
 	}
 
-	.sidebar .logo-container > img {
+	.mobile-topbar .logo-container > img {
 		max-width: 35px;
 		max-height: 35px;
+		margin-left: 20px;
+		margin-top: 5px;
+		margin-bottom: 5px;
 	}
 
-	.sidebar-menu {
-		position: fixed;
+	.mobile-topbar {
+		display: flex;
+		flex-direction: row;
+		position: sticky;
 		z-index: 10;
 		font-size: 2rem;
 		cursor: pointer;
-		width: 45px;
+		height: 45px;
+		width: 100%;
 		left: 0;
 		top: 0;
-		text-align: center;
-		display: block;
-		border-bottom: 1px solid;
-		border-right: 1px solid;
-		height: 45px;
 	}
 
-	.rustdoc.source > .sidebar > .sidebar-menu {
+	.source .mobile-topbar {
 		display: none;
 	}
 
-	/* We do NOT hide this element so that alternative device readers still have this information
-	   available. */
-	.sidebar-elems {
-		position: fixed;
-		z-index: 1;
-		top: 45px;
-		bottom: 0;
-		width: 246px;
-		/* We move the sidebar to the left by its own width so it doesn't appear. */
-		left: -246px;
-		overflow-y: auto;
-		border-right: 1px solid;
-	}
-
-	.sidebar > .block.version {
-		overflow: hidden;
-		border-bottom: none;
-		margin-bottom: 0;
-		height: 100%;
-		padding-left: 12px;
-	}
-	.sidebar > .block.version > div.narrow-helper {
-		float: left;
-		width: 1px;
-		height: 100%;
-	}
-	.sidebar > .block.version > p {
-		/* hide Version text if too narrow */
-		margin: 0;
-		min-width: 55px;
-		/* vertically center */
-		display: flex;
-		align-items: center;
-		height: 100%;
+	.sidebar-menu-toggle {
+		width: 45px;
+		border: none;
 	}
 
-	nav.sub {
-		width: calc(100% - 32px);
+	.source nav:not(.sidebar).sub {
 		margin-left: 32px;
-		margin-bottom: 10px;
 	}
 
-	.source nav:not(.sidebar).sub {
-		margin-left: 32px;
+	/* Space is at a premium on mobile, so remove the theme-picker icon. */
+	#theme-picker {
+		display: none;
+		width: 0;
 	}
 
 	.content {
@@ -1919,28 +1906,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		height: 50px;
 	}
 
-	.show-it, .sidebar-elems:focus-within {
-		z-index:  2;
-		left: 0;
-	}
-
-	.show-it > .block.items {
-		margin: 8px 0;
-	}
-
-	.show-it > .block.items > ul {
-		margin: 0;
-	}
-
-	.show-it > .block.items > ul > li {
-		text-align: center;
-		margin: 2px 0;
-	}
-
-	.show-it > .block.items > ul > li > a {
-		font-size: 1.3125rem;
-	}
-
 	/* Because of ios, we need to actually have a full height sidebar title so the
 	 * actual sidebar can show up. But then we need to make it transparent so we don't
 	 * hide content. The filler just allows to create the background for the sidebar
@@ -1961,10 +1926,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		left: -11px;
 	}
 
-	#all-types {
-		margin: 10px;
-	}
-
 	.sidebar.expanded #sidebar-toggle {
 		font-size: 1.5rem;
 	}
@@ -2070,16 +2031,10 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 	}
 
 	#crate-search {
-		width: 100%;
 		border-radius: 4px;
 		border: 0;
 	}
 
-	#crate-search + .search-input {
-		width: calc(100% + 71px);
-		margin-left: -36px;
-	}
-
 	#theme-picker, #settings-menu {
 		padding: 5px;
 		width: 31px;
@@ -2099,9 +2054,14 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 	}
 
 	.docblock code {
+		overflow-wrap: break-word;
 		overflow-wrap: anywhere;
 	}
 
+	.docblock table code {
+		overflow-wrap: normal;
+	}
+
 	.sub-container {
 		flex-direction: column;
 	}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 23ee87a4e68..69097b81b9f 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -57,7 +57,7 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #191f26;
 }
 
-.sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
 	background-color: #14191f;
 }
 
@@ -100,12 +100,6 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #14191f;
 }
 
-.sidebar .location {
-	border-color: #000;
-	background-color: #0f1419;
-	color: #fff;
-}
-
 .sidebar-elems .location {
 	color: #ff7733;
 }
@@ -114,15 +108,6 @@ pre, .rustdoc.source .example-wrap {
 	color: #fff;
 }
 
-.sidebar .version {
-	border-bottom-color: #424c57;
-}
-
-.sidebar-title {
-	border-top-color: #5c6773;
-	border-bottom-color: #5c6773;
-}
-
 .block a:hover {
 	background: transparent;
 	color: #ffb44c;
@@ -209,9 +194,6 @@ pre, .rustdoc.source .example-wrap {
 pre.rust .comment { color: #788797; }
 pre.rust .doccomment { color: #a1ac88; }
 
-nav:not(.sidebar) {
-	border-bottom-color: #424c57;
-}
 nav.main .current {
 	border-top-color: #5c6773;
 	border-bottom-color: #5c6773;
@@ -228,7 +210,8 @@ a.anchor,
 .small-section-header a,
 #source-sidebar a,
 pre.rust a,
-.sidebar a,
+.sidebar h2 a,
+.sidebar h3 a,
 .in-band a {
 	color: #c5c5c5;
 }
@@ -299,7 +282,8 @@ details.undocumented > summary::before {
 	border-color: #5c6773;
 }
 
-.since {
+.rightside,
+.out-of-band {
 	color: grey;
 }
 
@@ -580,13 +564,6 @@ kbd {
 	}
 }
 
-#all-types {
-	background-color: #14191f;
-}
-#all-types:hover {
-	background-color: rgba(70, 70, 70, 0.33);
-}
-
 .search-results .result-name span.alias {
 	color: #c5c5c5;
 }
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 2db725c9b4e..39165b2fc05 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -28,7 +28,7 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #2A2A2A;
 }
 
-.sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
 	background-color: #505050;
 }
 
@@ -69,21 +69,6 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #565656;
 }
 
-.sidebar .location {
-	border-color: #fff;
-	background: #575757;
-	color: #DDD;
-}
-
-.sidebar .version {
-	border-bottom-color: #DDD;
-}
-
-.sidebar-title {
-	border-top-color: #777;
-	border-bottom-color: #777;
-}
-
 .block a:hover {
 	background: #444;
 }
@@ -166,9 +151,6 @@ a.result-keyword:focus { background-color: #884719; }
 pre.rust .comment { color: #8d8d8b; }
 pre.rust .doccomment { color: #8ca375; }
 
-nav:not(.sidebar) {
-	border-bottom-color: #4e4e4e;
-}
 nav.main .current {
 	border-top-color: #eee;
 	border-bottom-color: #eee;
@@ -186,7 +168,8 @@ a.anchor,
 .small-section-header a,
 #source-sidebar a,
 pre.rust a,
-.sidebar a,
+.sidebar h2 a,
+.sidebar h3 a,
 .in-band a {
 	color: #ddd;
 }
@@ -256,7 +239,8 @@ details.undocumented > summary::before {
 	background: rgba(0,0,0,0);
 }
 
-.since {
+.rightside,
+.out-of-band {
 	color: grey;
 }
 
@@ -452,13 +436,6 @@ kbd {
 	}
 }
 
-#all-types {
-	background-color: #505050;
-}
-#all-types:hover {
-	background-color: #606060;
-}
-
 .search-results .result-name span.alias {
 	color: #fff;
 }
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 3c8dbeb98c5..448c9ac603c 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -30,7 +30,7 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #F5F5F5;
 }
 
-.sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
 	background-color: #F5F5F5;
 }
 
@@ -69,21 +69,6 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #f1f1f1;
 }
 
-.sidebar .location {
-	border-color: #000;
-	background-color: #fff;
-	color: #333;
-}
-
-.sidebar .version {
-	border-bottom-color: #DDD;
-}
-
-.sidebar-title {
-	border-top-color: #777;
-	border-bottom-color: #777;
-}
-
 .block a:hover {
 	background: #F5F5F5;
 }
@@ -163,9 +148,6 @@ a.result-keyword:focus { background-color: #afc6e4; }
 .content .fnname { color: #AD7C37; }
 .content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; }
 
-nav:not(.sidebar) {
-	border-bottom-color: #e0e0e0;
-}
 nav.main .current {
 	border-top-color: #000;
 	border-bottom-color: #000;
@@ -183,7 +165,8 @@ a.anchor,
 .small-section-header a,
 #source-sidebar a,
 pre.rust a,
-.sidebar a,
+.sidebar h2 a,
+.sidebar h3 a,
 .in-band a {
 	color: #000;
 }
@@ -243,6 +226,11 @@ details.undocumented > summary::before {
 	border-color: #bfbfbf;
 }
 
+.rightside,
+.out-of-band {
+	color: grey;
+}
+
 .result-name .primitive > i, .result-name .keyword > i {
 	color: black;
 }
@@ -435,13 +423,6 @@ kbd {
 	}
 }
 
-#all-types {
-	background-color: #fff;
-}
-#all-types:hover {
-	background-color: #f9f9f9;
-}
-
 .search-results .result-name span.alias {
 	color: #000;
 }
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index f41c1bd817a..161b95d9993 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -67,6 +67,13 @@ function resourcePath(basename, extension) {
             ty: sidebarVars.attributes["data-ty"].value,
             relpath: sidebarVars.attributes["data-relpath"].value,
         };
+        // FIXME: It would be nicer to generate this text content directly in HTML,
+        // but with the current code it's hard to get the right information in the right place.
+        var mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
+        var locationTitle = document.querySelector(".sidebar h2.location");
+        if (mobileLocationTitle && locationTitle) {
+            mobileLocationTitle.innerText = locationTitle.innerText;
+        }
     }
 }());
 
@@ -129,10 +136,15 @@ function hideThemeButtonState() {
 
 // Set up the theme picker list.
 (function () {
+    if (!document.location.href.startsWith("file:///")) {
+        return;
+    }
     var themeChoices = getThemesElement();
     var themePicker = getThemePickerElement();
     var availableThemes = getVar("themes").split(",");
 
+    removeClass(themeChoices.parentElement, "hidden");
+
     function switchThemeButtonState() {
         if (themeChoices.style.display === "block") {
             hideThemeButtonState();
@@ -283,9 +295,6 @@ function hideThemeButtonState() {
                 loadSearch();
             }
 
-            // `crates{version}.js` should always be loaded before this script, so we can use it
-            // safely.
-            searchState.addCrateDropdown(window.ALL_CRATES);
             var params = searchState.getQueryStringParams();
             if (params.search !== undefined) {
                 var search = searchState.outputElement();
@@ -295,30 +304,6 @@ function hideThemeButtonState() {
                 loadSearch();
             }
         },
-        addCrateDropdown: function(crates) {
-            var elem = document.getElementById("crate-search");
-
-            if (!elem) {
-                return;
-            }
-            var savedCrate = getSettingValue("saved-filter-crate");
-            for (var i = 0, len = crates.length; i < len; ++i) {
-                var option = document.createElement("option");
-                option.value = crates[i];
-                option.innerText = crates[i];
-                elem.appendChild(option);
-                // Set the crate filter from saved storage, if the current page has the saved crate
-                // filter.
-                //
-                // If not, ignore the crate filter -- we want to support filtering for crates on
-                // sites like doc.rust-lang.org where the crates may differ from page to page while
-                // on the
-                // same domain.
-                if (crates[i] === savedCrate) {
-                    elem.value = savedCrate;
-                }
-            }
-        },
     };
 
     function getPageId() {
@@ -331,37 +316,6 @@ function hideThemeButtonState() {
         return null;
     }
 
-    function showSidebar() {
-        var elems = document.getElementsByClassName("sidebar-elems")[0];
-        if (elems) {
-            addClass(elems, "show-it");
-        }
-        var sidebar = document.getElementsByClassName("sidebar")[0];
-        if (sidebar) {
-            addClass(sidebar, "mobile");
-            var filler = document.getElementById("sidebar-filler");
-            if (!filler) {
-                var div = document.createElement("div");
-                div.id = "sidebar-filler";
-                sidebar.appendChild(div);
-            }
-        }
-    }
-
-    function hideSidebar() {
-        var elems = document.getElementsByClassName("sidebar-elems")[0];
-        if (elems) {
-            removeClass(elems, "show-it");
-        }
-        var sidebar = document.getElementsByClassName("sidebar")[0];
-        removeClass(sidebar, "mobile");
-        var filler = document.getElementById("sidebar-filler");
-        if (filler) {
-            filler.remove();
-        }
-        document.getElementsByTagName("body")[0].style.marginTop = "";
-    }
-
     var toggleAllDocsId = "toggle-all-docs";
     var main = document.getElementById(MAIN_ID);
     var savedHash = "";
@@ -396,7 +350,8 @@ function hideThemeButtonState() {
 
     function onHashChange(ev) {
         // If we're in mobile mode, we should hide the sidebar in any case.
-        hideSidebar();
+        var sidebar = document.getElementsByClassName("sidebar")[0];
+        removeClass(sidebar, "shown");
         handleHashes(ev);
     }
 
@@ -888,6 +843,11 @@ function hideThemeButtonState() {
         });
     }());
 
+    function hideSidebar() {
+        var sidebar = document.getElementsByClassName("sidebar")[0];
+        removeClass(sidebar, "shown");
+    }
+
     function handleClick(id, f) {
         var elem = document.getElementById(id);
         if (elem) {
@@ -897,6 +857,9 @@ function hideThemeButtonState() {
     handleClick("help-button", function(ev) {
         displayHelp(true, ev);
     });
+    handleClick(MAIN_ID, function() {
+        hideSidebar();
+    });
 
     onEachLazy(document.getElementsByTagName("a"), function(el) {
         // For clicks on internal links (<A> tags with a hash property), we expand the section we're
@@ -905,6 +868,7 @@ function hideThemeButtonState() {
         if (el.hash) {
             el.addEventListener("click", function() {
                 expandSection(el.hash.slice(1));
+                hideSidebar();
             });
         }
     });
@@ -924,16 +888,16 @@ function hideThemeButtonState() {
         };
     });
 
-    var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
-    if (sidebar_menu) {
-        sidebar_menu.onclick = function() {
+    var sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];
+    if (sidebar_menu_toggle) {
+        sidebar_menu_toggle.addEventListener("click", function() {
             var sidebar = document.getElementsByClassName("sidebar")[0];
-            if (hasClass(sidebar, "mobile")) {
-                hideSidebar();
+            if (!hasClass(sidebar, "shown")) {
+                addClass(sidebar, "shown");
             } else {
-                showSidebar();
+                removeClass(sidebar, "shown");
             }
-        };
+        });
     }
 
     var buildHelperPopup = function() {
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index e859431e1f1..104464b3881 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1126,15 +1126,18 @@ window.initSearch = function(rawSearchIndex) {
             }
         }
 
-        let crates = `<select id="crate-search"><option value="All crates">All crates</option>`;
-        for (let c of window.ALL_CRATES) {
-            crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
+        let crates = "";
+        if (window.ALL_CRATES.length > 1) {
+            crates = ` in <select id="crate-search"><option value="All crates">All crates</option>`;
+            for (let c of window.ALL_CRATES) {
+                crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
+            }
+            crates += `</select>`;
         }
-        crates += `</select>`;
         var output = `<div id="search-settings">
             <h1 class="search-results-title">Results for ${escape(query.query)} ` +
             (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
-            ` in ${crates} ` +
+            crates +
             `</div><div id="titles">` +
             makeTabHeader(0, "In Names", ret_others[1]) +
             makeTabHeader(1, "In Parameters", ret_in_args[1]) +
@@ -1148,7 +1151,10 @@ window.initSearch = function(rawSearchIndex) {
         resultsElem.appendChild(ret_returned[0]);
 
         search.innerHTML = output;
-        document.getElementById("crate-search").addEventListener("input", updateCrate);
+        let crateSearch = document.getElementById("crate-search");
+        if (crateSearch) {
+            crateSearch.addEventListener("input", updateCrate);
+        }
         search.appendChild(resultsElem);
         // Reset focused elements.
         searchState.focusedByTab = [null, null, null];
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 4f10e14e855..e5c7e1ea1a0 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -1,15 +1,18 @@
 // Local js definitions:
 /* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
+/* global addClass, removeClass */
 
 (function () {
     function changeSetting(settingName, value) {
         updateLocalStorage("rustdoc-" + settingName, value);
 
         switch (settingName) {
+            case "theme":
             case "preferred-dark-theme":
             case "preferred-light-theme":
             case "use-system-theme":
                 updateSystemTheme();
+                updateLightAndDark();
                 break;
         }
     }
@@ -29,7 +32,32 @@
         }
     }
 
+    function showLightAndDark() {
+        addClass(document.getElementById("theme").parentElement.parentElement, "hidden");
+        removeClass(document.getElementById("preferred-light-theme").parentElement.parentElement,
+            "hidden");
+        removeClass(document.getElementById("preferred-dark-theme").parentElement.parentElement,
+            "hidden");
+    }
+
+    function hideLightAndDark() {
+        addClass(document.getElementById("preferred-light-theme").parentElement.parentElement,
+            "hidden");
+        addClass(document.getElementById("preferred-dark-theme").parentElement.parentElement,
+            "hidden");
+        removeClass(document.getElementById("theme").parentElement.parentElement, "hidden");
+    }
+
+    function updateLightAndDark() {
+        if (getSettingValue("use-system-theme") !== "false") {
+            showLightAndDark();
+        } else {
+            hideLightAndDark();
+        }
+    }
+
     function setEvents() {
+        updateLightAndDark();
         onEachLazy(document.getElementsByClassName("slider"), function(elem) {
             var toggle = elem.previousElementSibling;
             var settingId = toggle.id;
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 81dc0b2fb1e..498f60e9f25 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -139,7 +139,7 @@ function createSourceSidebar() {
                                       currentFile, hasFoundFile);
     });
 
-    container.insertBefore(sidebar, document.querySelector(".sidebar-logo").nextSibling);
+    container.appendChild(sidebar);
     // Focus on the current file in the source files sidebar.
     var selected_elem = sidebar.getElementsByClassName("selected")[0];
     if (typeof selected_elem !== "undefined") {
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index d8b3ba92dcb..2394df4c715 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -187,22 +187,25 @@ var updateSystemTheme = (function() {
     var mql = window.matchMedia("(prefers-color-scheme: dark)");
 
     function handlePreferenceChange(mql) {
+        let use = function(theme) {
+            switchTheme(window.currentTheme, window.mainTheme, theme, true);
+        };
         // maybe the user has disabled the setting in the meantime!
         if (getSettingValue("use-system-theme") !== "false") {
             var lightTheme = getSettingValue("preferred-light-theme") || "light";
             var darkTheme = getSettingValue("preferred-dark-theme") || "dark";
 
             if (mql.matches) {
-                // prefers a dark theme
-                switchTheme(window.currentTheme, window.mainTheme, darkTheme, true);
+                use(darkTheme);
             } else {
                 // prefers a light theme, or has no preference
-                switchTheme(window.currentTheme, window.mainTheme, lightTheme, true);
+                use(lightTheme);
             }
-
             // note: we save the theme so that it doesn't suddenly change when
             // the user disables "use-system-theme" and reloads the page or
             // navigates to another page
+        } else {
+            use(getSettingValue("theme"));
         }
     }
 
diff --git a/src/librustdoc/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md
index fff65e3b5ff..fff65e3b5ff 100644
--- a/src/librustdoc/templates/STYLE.md
+++ b/src/librustdoc/html/templates/STYLE.md
diff --git a/src/librustdoc/templates/page.html b/src/librustdoc/html/templates/page.html
index 02808754b53..1322b854b7f 100644
--- a/src/librustdoc/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -72,8 +72,20 @@
     </div> {#- -#}
     <![endif]--> {#- -#}
     {{- layout.external_html.before_content|safe -}}
+    <nav class="mobile-topbar"> {#- -#}
+        <button class="sidebar-menu-toggle">&#9776;</button> {#- -#}
+        <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+            <div class="logo-container"> {#- -#}
+            {%- if !layout.logo.is_empty() -%}
+                <img src="{{layout.logo}}" alt="logo"> {#- -#}
+            {%- else -%}
+                <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
+            {%- endif -%}
+            </div>
+        </a> {#- -#}
+        <h2 class="location"></h2>
+    </nav>
     <nav class="sidebar"> {#- -#}
-        <div class="sidebar-menu" role="button">&#9776;</div> {#- -#}
         <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
             <div class="logo-container"> {#- -#}
                 {%- if !layout.logo.is_empty()  %}
@@ -96,7 +108,7 @@
                     {%- endif -%}
                 </a> {#- -#}
                 <nav class="sub"> {#- -#}
-                    <div class="theme-picker"> {#- -#}
+                    <div class="theme-picker hidden"> {#- -#}
                         <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
                             <img width="18" height="18" alt="Pick another theme!" {# -#}
                              src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
diff --git a/src/librustdoc/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index 459b01a9960..459b01a9960 100644
--- a/src/librustdoc/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index c8efa4bbbcc..e77bd5c9223 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -162,7 +162,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
     fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
         use clean::TypeBindingKind::*;
         match kind {
-            Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)),
+            Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
             Constraint { bounds } => {
                 TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
             }
@@ -452,6 +452,15 @@ impl FromWithTcx<clean::Type> for Type {
     }
 }
 
+impl FromWithTcx<clean::Term> for Term {
+    fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term {
+        match term {
+            clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)),
+            clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)),
+        }
+    }
+}
+
 impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
     fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
         let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 81fbfd9fdbd..8f484766d9a 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -7,7 +7,7 @@
 mod conversions;
 
 use std::cell::RefCell;
-use std::fs::File;
+use std::fs::{create_dir_all, File};
 use std::path::PathBuf;
 use std::rc::Rc;
 
@@ -18,13 +18,14 @@ use rustc_session::Session;
 
 use rustdoc_json_types as types;
 
-use crate::clean;
 use crate::clean::types::{ExternalCrate, ExternalLocation};
 use crate::config::RenderOptions;
+use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
 use crate::json::conversions::{from_item_id, IntoWithTcx};
+use crate::{clean, try_err};
 
 #[derive(Clone)]
 crate struct JsonRenderer<'tcx> {
@@ -171,8 +172,21 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     /// the hashmap because certain items (traits and types) need to have their mappings for trait
     /// implementations filled out before they're inserted.
     fn item(&mut self, item: clean::Item) -> Result<(), Error> {
+        let local_blanket_impl = match item.def_id {
+            clean::ItemId::Blanket { impl_id, .. } => impl_id.is_local(),
+            clean::ItemId::Auto { .. }
+            | clean::ItemId::DefId(_)
+            | clean::ItemId::Primitive(_, _) => false,
+        };
+
         // Flatten items that recursively store other items
-        item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
+        // FIXME(CraftSpider): We skip children of local blanket implementations, as we'll have
+        //     already seen the actual generic impl, and the generated ones don't need documenting.
+        //     This is necessary due to the visibility, return type, and self arg of the generated
+        //     impls not quite matching, and will no longer be necessary when the mismatch is fixed.
+        if !local_blanket_impl {
+            item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
+        }
 
         let id = item.def_id;
         if let Some(mut new_item) = self.convert_item(item) {
@@ -256,10 +270,13 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .collect(),
             format_version: types::FORMAT_VERSION,
         };
-        let mut p = self.out_path.clone();
+        let out_dir = self.out_path.clone();
+        try_err!(create_dir_all(&out_dir), out_dir);
+
+        let mut p = out_dir;
         p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
         p.set_extension("json");
-        let file = File::create(&p).map_err(|error| Error { error: error.to_string(), file: p })?;
+        let file = try_err!(File::create(&p), p);
         serde_json::ser::to_writer(&file, &output).unwrap();
         Ok(())
     }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 1a9794e75bc..7dbf00420de 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -305,16 +305,15 @@ crate enum FragmentKind {
 
 impl ItemFragment {
     /// Create a fragment for an associated item.
-    ///
-    /// `is_prototype` is whether this associated item is a trait method
-    /// without a default definition.
-    fn from_assoc_item(def_id: DefId, kind: ty::AssocKind, is_prototype: bool) -> Self {
-        match kind {
+    #[instrument(level = "debug")]
+    fn from_assoc_item(item: &ty::AssocItem) -> Self {
+        let def_id = item.def_id;
+        match item.kind {
             ty::AssocKind::Fn => {
-                if is_prototype {
-                    ItemFragment(FragmentKind::TyMethod, def_id)
-                } else {
+                if item.defaultness.has_value() {
                     ItemFragment(FragmentKind::Method, def_id)
+                } else {
+                    ItemFragment(FragmentKind::TyMethod, def_id)
                 }
             }
             ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id),
@@ -473,8 +472,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             tcx.associated_items(impl_)
                 .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
                 .map(|item| {
-                    let kind = item.kind;
-                    let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+                    let fragment = ItemFragment::from_assoc_item(item);
                     (Res::Primitive(prim_ty), fragment)
                 })
         })
@@ -726,8 +724,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                         .flatten();
 
                     assoc_item.map(|item| {
-                        let kind = item.kind;
-                        let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+                        let fragment = ItemFragment::from_assoc_item(&item);
                         (root_res, fragment)
                     })
                 })
@@ -765,20 +762,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     // To handle that properly resolve() would have to support
                     // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
                     .or_else(|| {
-                        let item = resolve_associated_trait_item(
+                        resolve_associated_trait_item(
                             tcx.type_of(did),
                             module_id,
                             item_name,
                             ns,
                             self.cx,
-                        );
-                        debug!("got associated item {:?}", item);
-                        item
+                        )
                     });
 
+                debug!("got associated item {:?}", assoc_item);
+
                 if let Some(item) = assoc_item {
-                    let kind = item.kind;
-                    let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+                    let fragment = ItemFragment::from_assoc_item(&item);
                     return Some((root_res, fragment));
                 }
 
@@ -813,11 +809,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 .associated_items(did)
                 .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did)
                 .map(|item| {
-                    let fragment = ItemFragment::from_assoc_item(
-                        item.def_id,
-                        item.kind,
-                        !item.defaultness.has_value(),
-                    );
+                    let fragment = ItemFragment::from_assoc_item(item);
                     let res = Res::Def(item.kind.as_def_kind(), item.def_id);
                     (res, fragment)
                 }),
@@ -883,30 +875,56 @@ fn resolve_associated_trait_item<'a>(
 
     // Next consider explicit impls: `impl MyTrait for MyType`
     // Give precedence to inherent impls.
-    let traits = traits_implemented_by(cx, ty, module);
+    let traits = trait_impls_for(cx, ty, module);
     debug!("considering traits {:?}", traits);
-    let mut candidates = traits.iter().filter_map(|&trait_| {
-        cx.tcx.associated_items(trait_).find_by_name_and_namespace(
-            cx.tcx,
-            Ident::with_dummy_span(item_name),
-            ns,
-            trait_,
-        )
+    let mut candidates = traits.iter().filter_map(|&(impl_, trait_)| {
+        cx.tcx
+            .associated_items(trait_)
+            .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_)
+            .map(|trait_assoc| {
+                trait_assoc_to_impl_assoc_item(cx.tcx, impl_, trait_assoc.def_id)
+                    .unwrap_or(trait_assoc)
+            })
     });
     // FIXME(#74563): warn about ambiguity
     debug!("the candidates were {:?}", candidates.clone().collect::<Vec<_>>());
     candidates.next().copied()
 }
 
-/// Given a type, return all traits in scope in `module` implemented by that type.
+/// Find the associated item in the impl `impl_id` that corresponds to the
+/// trait associated item `trait_assoc_id`.
+///
+/// This function returns `None` if no associated item was found in the impl.
+/// This can occur when the trait associated item has a default value that is
+/// not overriden in the impl.
+///
+/// This is just a wrapper around [`TyCtxt::impl_item_implementor_ids()`] and
+/// [`TyCtxt::associated_item()`] (with some helpful logging added).
+#[instrument(level = "debug", skip(tcx))]
+fn trait_assoc_to_impl_assoc_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_id: DefId,
+    trait_assoc_id: DefId,
+) -> Option<&'tcx ty::AssocItem> {
+    let trait_to_impl_assoc_map = tcx.impl_item_implementor_ids(impl_id);
+    debug!(?trait_to_impl_assoc_map);
+    let impl_assoc_id = *trait_to_impl_assoc_map.get(&trait_assoc_id)?;
+    debug!(?impl_assoc_id);
+    let impl_assoc = tcx.associated_item(impl_assoc_id);
+    debug!(?impl_assoc);
+    Some(impl_assoc)
+}
+
+/// Given a type, return all trait impls in scope in `module` for that type.
+/// Returns a set of pairs of `(impl_id, trait_id)`.
 ///
 /// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
 /// So it is not stable to serialize cross-crate.
-fn traits_implemented_by<'a>(
+fn trait_impls_for<'a>(
     cx: &mut DocContext<'a>,
     ty: Ty<'a>,
     module: DefId,
-) -> FxHashSet<DefId> {
+) -> FxHashSet<(DefId, DefId)> {
     let mut resolver = cx.resolver.borrow_mut();
     let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
         resolver.access(|resolver| {
@@ -948,7 +966,7 @@ fn traits_implemented_by<'a>(
                     _ => false,
                 };
 
-            if saw_impl { Some(trait_) } else { None }
+            if saw_impl { Some((impl_, trait_)) } else { None }
         })
     });
     iter.collect()
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 90cb5d586c2..2cbb3324a5e 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -141,6 +141,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     })
                     .collect::<Vec<_>>()
             })
+            .chain([Cfg::Cfg(sym::test, None)].into_iter())
             .collect();
 
         self.cx.cache.exact_paths = self.exact_paths;
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 2abffbf977a9e8c6ca4174a08fe5c4d7781f0aa
+Subproject 6b3dbcc81a470e5da84576d63fcfc19e3b1154c
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 9466f84ffcd..618c8aab86a 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -148,7 +148,7 @@ pub struct TypeBinding {
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 pub enum TypeBindingKind {
-    Equality(Type),
+    Equality(Term),
     Constraint(Vec<GenericBound>),
 }
 
@@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
 pub enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
     RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: Type, rhs: Type },
+    EqPredicate { lhs: Type, rhs: Term },
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -361,6 +361,13 @@ pub enum TraitBoundModifier {
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
+pub enum Term {
+    Type(Type),
+    Constant(Constant),
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 #[serde(tag = "kind", content = "inner")]
 pub enum Type {
     /// Structs, enums, and traits
diff --git a/src/test/codegen/thread-local.rs b/src/test/codegen/thread-local.rs
index 5ac30d949fa..c59b088f7a6 100644
--- a/src/test/codegen/thread-local.rs
+++ b/src/test/codegen/thread-local.rs
@@ -19,7 +19,7 @@ thread_local!(static A: Cell<u32> = const { Cell::new(1) });
 // CHECK-LABEL: @get
 #[no_mangle]
 fn get() -> u32 {
-    // CHECK: %0 = load i32, i32* bitcast ({{.*}} [[TLS]] to i32*)
+    // CHECK: %0 = load i32, i32* {{.*}}[[TLS]]{{.*}}
     // CHECK-NEXT: ret i32 %0
     A.with(|a| a.get())
 }
@@ -27,7 +27,7 @@ fn get() -> u32 {
 // CHECK-LABEL: @set
 #[no_mangle]
 fn set(v: u32) {
-    // CHECK: store i32 %0, i32* bitcast ({{.*}} [[TLS]] to i32*)
+    // CHECK: store i32 %0, i32* {{.*}}[[TLS]]{{.*}}
     // CHECK-NEXT: ret void
     A.with(|a| a.set(v))
 }
diff --git a/src/test/incremental/cache_file_headers.rs b/src/test/incremental/cache_file_headers.rs
index 7f1ef886ac8..9cf611c3379 100644
--- a/src/test/incremental/cache_file_headers.rs
+++ b/src/test/incremental/cache_file_headers.rs
@@ -7,7 +7,7 @@
 
 // The `l33t haxx0r` Rust compiler is known to produce incr. comp. artifacts
 // that are outrageously incompatible with just about anything, even itself:
-//[rpass1] rustc-env:RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER="l33t haxx0r rustc 2.1 LTS"
+//[rpass1] rustc-env:RUSTC_FORCE_RUSTC_VERSION="l33t haxx0r rustc 2.1 LTS"
 
 // revisions:rpass1 rpass2
 // compile-flags: -Z query-dep-graph
diff --git a/src/test/run-make-fulldeps/codegen-options-parsing/Makefile b/src/test/run-make-fulldeps/codegen-options-parsing/Makefile
index 39e9a9bdd6b..f1410b69b3f 100644
--- a/src/test/run-make-fulldeps/codegen-options-parsing/Makefile
+++ b/src/test/run-make-fulldeps/codegen-options-parsing/Makefile
@@ -24,8 +24,8 @@ all:
 	$(RUSTC) -C lto dummy.rs
 
 	# Should not link dead code...
-	$(RUSTC) -Z print-link-args dummy.rs 2>&1 | \
+	$(RUSTC) --print link-args dummy.rs 2>&1 | \
 		$(CGREP) -e '--gc-sections|-z[^ ]* [^ ]*<ignore>|-dead_strip|/OPT:REF'
 	# ... unless you specifically ask to keep it
-	$(RUSTC) -Z print-link-args -C link-dead-code dummy.rs 2>&1 | \
+	$(RUSTC) --print link-args -C link-dead-code dummy.rs 2>&1 | \
 		$(CGREP) -ve '--gc-sections|-z[^ ]* [^ ]*<ignore>|-dead_strip|/OPT:REF'
diff --git a/src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile b/src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile
index fd66702db7f..091508cd805 100644
--- a/src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile
+++ b/src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile
@@ -27,7 +27,7 @@ all:
 	$(RUSTC) b.rs --extern a=$(TMPDIR)/liba$(EXT) --crate-type=bin -Crpath $(FLAGS)
 	$(call RUN,b)
 	# Now re-compile a.rs with another rustc version
-	RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
+	RUSTC_FORCE_RUSTC_VERSION=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
 	# After compiling with a different rustc version, write symbols to disk again.
 	$(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsafter
 	# As a sanity check, test if the symbols changed:
diff --git a/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile b/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile
index 1268022e37b..0a50859cdaa 100644
--- a/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile
+++ b/src/test/run-make-fulldeps/interdependent-c-libraries/Makefile
@@ -11,4 +11,4 @@
 all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar)
 	$(RUSTC) foo.rs
 	$(RUSTC) bar.rs
-	$(RUSTC) main.rs -Z print-link-args
+	$(RUSTC) main.rs --print link-args
diff --git a/src/test/run-make-fulldeps/link-arg/Makefile b/src/test/run-make-fulldeps/link-arg/Makefile
index d7c9fd27112..0360ede7625 100644
--- a/src/test/run-make-fulldeps/link-arg/Makefile
+++ b/src/test/run-make-fulldeps/link-arg/Makefile
@@ -1,5 +1,5 @@
 -include ../tools.mk
-RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" -Z print-link-args
+RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" --print link-args
 
 all:
 	$(RUSTC) $(RUSTC_FLAGS) empty.rs | $(CGREP) lfoo lbar
diff --git a/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile b/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile
index 09e6ae0bbf7..3ffbba9444b 100644
--- a/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile
+++ b/src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile
@@ -6,5 +6,5 @@ all:
 	$(RUSTC) bar.rs \
 		--extern foo1=$(TMPDIR)/libfoo-a.rlib \
 		--extern foo2=$(TMPDIR)/libfoo-b.rlib \
-		-Z print-link-args
+		--print link-args
 	$(call RUN,bar)
diff --git a/src/test/run-make-fulldeps/no-builtins-lto/Makefile b/src/test/run-make-fulldeps/no-builtins-lto/Makefile
index b9688f16c64..2e41be39d5d 100644
--- a/src/test/run-make-fulldeps/no-builtins-lto/Makefile
+++ b/src/test/run-make-fulldeps/no-builtins-lto/Makefile
@@ -6,4 +6,4 @@ all:
 	# Build an executable that depends on that crate using LTO. The no_builtins crate doesn't
 	# participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by
 	# grepping the linker arguments.
-	$(RUSTC) main.rs -C lto -Z print-link-args | $(CGREP) 'libno_builtins.rlib'
+	$(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib'
diff --git a/src/test/run-make-fulldeps/redundant-libs/Makefile b/src/test/run-make-fulldeps/redundant-libs/Makefile
index 8468d102bec..e09841fb42e 100644
--- a/src/test/run-make-fulldeps/redundant-libs/Makefile
+++ b/src/test/run-make-fulldeps/redundant-libs/Makefile
@@ -16,7 +16,7 @@ RUSTC_FLAGS = \
     -l foo \
     -l static=baz \
     -l foo \
-    -Z print-link-args
+    --print link-args
 
 all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz)
 	$(RUSTC) $(RUSTC_FLAGS) main.rs
diff --git a/src/test/run-make-fulldeps/static-nobundle/Makefile b/src/test/run-make-fulldeps/static-nobundle/Makefile
index abc32d4423b..8f78c401a11 100644
--- a/src/test/run-make-fulldeps/static-nobundle/Makefile
+++ b/src/test/run-make-fulldeps/static-nobundle/Makefile
@@ -13,9 +13,9 @@ all: $(call NATIVE_STATICLIB,aaa)
 	nm $(TMPDIR)/libbbb.rlib | $(CGREP) -e "U _*native_func"
 
 	# Check that aaa gets linked (either as `-l aaa` or `aaa.lib`) when building ccc.
-	$(RUSTC) ccc.rs -C prefer-dynamic --crate-type=dylib -Z print-link-args | $(CGREP) -e '-l[" ]*aaa|aaa\.lib'
+	$(RUSTC) ccc.rs -C prefer-dynamic --crate-type=dylib --print link-args | $(CGREP) -e '-l[" ]*aaa|aaa\.lib'
 
 	# Check that aaa does NOT get linked when building ddd.
-	$(RUSTC) ddd.rs -Z print-link-args | $(CGREP) -ve '-l[" ]*aaa|aaa\.lib'
+	$(RUSTC) ddd.rs --print link-args | $(CGREP) -ve '-l[" ]*aaa|aaa\.lib'
 
 	$(call RUN,ddd)
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
index 0f874333fa0..4af8b43ea84 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
@@ -1,12 +1,17 @@
 # Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.
 
-# only-i686-pc-windows-msvc
+# only-x86
+# only-windows
 
 -include ../../run-make-fulldeps/tools.mk
 
 all:
 	$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
+ifdef IS_MSVC
 	$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll
+else
+	$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
+endif
 	$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
 	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
index ba0f1418aba..165792b0490 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
@@ -62,9 +62,12 @@ pub fn library_function() {
         fastcall_fn_2(16, 3.5);
         fastcall_fn_3(3.5);
         fastcall_fn_4(1, 2, 3.0);
-        fastcall_fn_5(S { x: 1, y: 2 }, 16);
+        // FIXME: 91167
+        // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
+        // on i686-pc-windows-gnu; commenting these out until the indicated issue is fixed.
+        //fastcall_fn_5(S { x: 1, y: 2 }, 16);
         fastcall_fn_6(Some(&S { x: 10, y: 12 }));
-        fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
+        //fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
         fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
         fastcall_fn_9(1, 3.0);
     }
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/output.txt b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
index be598a22027..348bad63ed0 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
@@ -11,8 +11,6 @@ fastcall_fn_1(14)
 fastcall_fn_2(16, 3.5)
 fastcall_fn_3(3.5)
 fastcall_fn_4(1, 2, 3.0)
-fastcall_fn_5(S { x: 1, y: 2 }, 16)
 fastcall_fn_6(S { x: 10, y: 12 })
-fastcall_fn_7(S2 { x: 15, y: 16 }, 3)
 fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
 fastcall_fn_9(1, 3.0)
diff --git a/src/test/run-make/raw-dylib-c/Makefile b/src/test/run-make/raw-dylib-c/Makefile
index 26ab4d34764..166305672e6 100644
--- a/src/test/run-make/raw-dylib-c/Makefile
+++ b/src/test/run-make/raw-dylib-c/Makefile
@@ -1,14 +1,19 @@
 # Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
 
-# only-windows-msvc
+# only-windows
 
 -include ../../run-make-fulldeps/tools.mk
 
 all:
 	$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
 	$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
+ifdef IS_MSVC
 	$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
 	$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+else
+	$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
+	$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
+endif
 	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
 	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
diff --git a/src/test/run-make/raw-dylib-link-ordinal/Makefile b/src/test/run-make/raw-dylib-link-ordinal/Makefile
index 04b257d0632..0e84a749b05 100644
--- a/src/test/run-make/raw-dylib-link-ordinal/Makefile
+++ b/src/test/run-make/raw-dylib-link-ordinal/Makefile
@@ -1,12 +1,16 @@
 # Test the behavior of #[link(.., kind = "raw-dylib")] and #[link_ordinal] on windows-msvc
 
-# only-windows-msvc
+# only-windows
 
 -include ../../run-make-fulldeps/tools.mk
 
 all:
 	$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
+ifdef IS_MSVC
 	$(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+else
+	$(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll
+endif
 	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
 	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile b/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile
new file mode 100644
index 00000000000..69f62669d62
--- /dev/null
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile
@@ -0,0 +1,23 @@
+# Test the behavior of #[link(.., kind = "raw-dylib")], #[link_ordinal], and alternative calling conventions on i686 windows.
+
+# only-x86
+# only-windows
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+	$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
+ifdef IS_MSVC
+	$(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+else
+	$(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll
+endif
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+	"$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt
+
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/actual_output.txt expected_output.txt
+else
+	$(DIFF) expected_output.txt "$(TMPDIR)"/actual_output.txt
+endif
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/driver.rs b/src/test/run-make/raw-dylib-stdcall-ordinal/driver.rs
new file mode 100644
index 00000000000..4059ede11fc
--- /dev/null
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/driver.rs
@@ -0,0 +1,5 @@
+extern crate raw_dylib_test;
+
+fn main() {
+    raw_dylib_test::library_function();
+}
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/expected_output.txt b/src/test/run-make/raw-dylib-stdcall-ordinal/expected_output.txt
new file mode 100644
index 00000000000..20157763745
--- /dev/null
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/expected_output.txt
@@ -0,0 +1,2 @@
+exported_function_stdcall(6)
+exported_function_fastcall(125)
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-gnu.def b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-gnu.def
new file mode 100644
index 00000000000..8d28d714b7e
--- /dev/null
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-gnu.def
@@ -0,0 +1,4 @@
+LIBRARY exporter
+EXPORTS
+    exported_function_stdcall@4 @15 NONAME
+    @exported_function_fastcall@4 @18 NONAME
\ No newline at end of file
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-msvc.def b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-msvc.def
new file mode 100644
index 00000000000..5a4c79a58ed
--- /dev/null
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-msvc.def
@@ -0,0 +1,4 @@
+LIBRARY exporter
+EXPORTS
+    _exported_function_stdcall@4 @15 NONAME
+    @exported_function_fastcall@4 @18 NONAME
\ No newline at end of file
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/exporter.c b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter.c
new file mode 100644
index 00000000000..1fb45bf010f
--- /dev/null
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+void __stdcall exported_function_stdcall(int i) {
+    printf("exported_function_stdcall(%d)\n", i);
+    fflush(stdout);
+}
+
+void __fastcall exported_function_fastcall(int i) {
+    printf("exported_function_fastcall(%d)\n", i);
+    fflush(stdout);
+}
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs b/src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs
new file mode 100644
index 00000000000..07dd3d7be9b
--- /dev/null
+++ b/src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs
@@ -0,0 +1,20 @@
+#![feature(raw_dylib)]
+
+#[link(name = "exporter", kind = "raw-dylib")]
+extern "stdcall" {
+    #[link_ordinal(15)]
+    fn imported_function_stdcall(i: i32);
+}
+
+#[link(name = "exporter", kind = "raw-dylib")]
+extern "fastcall" {
+    #[link_ordinal(18)]
+    fn imported_function_fastcall(i: i32);
+}
+
+pub fn library_function() {
+    unsafe {
+        imported_function_stdcall(6);
+        imported_function_fastcall(125);
+    }
+}
diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml
index e6758287d8c..2d48d21dc1b 100644
--- a/src/test/rustdoc-gui/anchors.goml
+++ b/src/test/rustdoc-gui/anchors.goml
@@ -20,7 +20,7 @@ assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)"
 
 assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
 
-assert-css: (".sidebar a", {"color": "rgb(0, 0, 0)"})
+assert-css: (".sidebar a", {"color": "rgb(56, 115, 173)"})
 assert-css: (".in-band a", {"color": "rgb(0, 0, 0)"})
 
 // We move the cursor over the "Implementations" title so the anchor is displayed.
diff --git a/src/test/rustdoc-gui/code-blocks-overflow.goml b/src/test/rustdoc-gui/code-blocks-overflow.goml
index ee4dad444e9..f93f3f0aefc 100644
--- a/src/test/rustdoc-gui/code-blocks-overflow.goml
+++ b/src/test/rustdoc-gui/code-blocks-overflow.goml
@@ -5,4 +5,4 @@ size: (1080, 600)
 assert-count: (".docblock > .example-wrap", 2)
 assert: ".docblock > .example-wrap > .language-txt"
 assert: ".docblock > .example-wrap > .rust-example-rendered"
-assert-css: (".docblock > .example-wrap > pre", {"width": "796px", "overflow-x": "auto"}, ALL)
+assert-css: (".docblock > .example-wrap > pre", {"width": "785.25px", "overflow-x": "auto"}, ALL)
diff --git a/src/test/rustdoc-gui/docblock-table-overflow.goml b/src/test/rustdoc-gui/docblock-table-overflow.goml
index 1b3006155d8..a9af88189a6 100644
--- a/src/test/rustdoc-gui/docblock-table-overflow.goml
+++ b/src/test/rustdoc-gui/docblock-table-overflow.goml
@@ -4,7 +4,7 @@ goto: file://|DOC_PATH|/lib2/long_table/struct.Foo.html
 size: (1100, 800)
 // Logically, the ".docblock" and the "<p>" should have the same scroll width.
 compare-elements-property: (".top-doc .docblock", ".top-doc .docblock > p", ["scrollWidth"])
-assert-property: (".top-doc .docblock", {"scrollWidth": "816"})
+assert-property: (".top-doc .docblock", {"scrollWidth": "801"})
 // However, since there is overflow in the <table>, its scroll width is bigger.
 assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"})
 
@@ -16,6 +16,6 @@ compare-elements-property: (
     "#implementations + details .docblock > p",
     ["scrollWidth"],
 )
-assert-property: ("#implementations + details .docblock", {"scrollWidth": "816"})
+assert-property: ("#implementations + details .docblock", {"scrollWidth": "801"})
 // However, since there is overflow in the <table>, its scroll width is bigger.
 assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"})
diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml
index 9db75c59d94..48e0156f1b8 100644
--- a/src/test/rustdoc-gui/headings.goml
+++ b/src/test/rustdoc-gui/headings.goml
@@ -15,7 +15,6 @@
 goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -55,7 +54,6 @@ assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2p
 goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -110,12 +108,11 @@ assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"
 assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
 
 assert-text: (".sidebar .others h3", "Modules")
-assert-css: (".sidebar .others h3", {"border-bottom-width": "1px"}, ALL)
+assert-css: (".sidebar .others h3", {"border-bottom-width": "0px"}, ALL)
 
 goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -148,9 +145,21 @@ assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "
 goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+
+goto: file://|DOC_PATH|/staged_api/struct.Foo.html
+show-text: true
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
+
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
+
+local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"}
+reload:
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
diff --git a/src/test/rustdoc-gui/item-info-width.goml b/src/test/rustdoc-gui/item-info-width.goml
index cdc00d34114..acb30141ce5 100644
--- a/src/test/rustdoc-gui/item-info-width.goml
+++ b/src/test/rustdoc-gui/item-info-width.goml
@@ -3,5 +3,5 @@ goto: file://|DOC_PATH|/lib2/struct.Foo.html
 // We set a fixed size so there is no chance of "random" resize.
 size: (1100, 800)
 // We check that ".item-info" is bigger than its content.
-assert-css: (".item-info", {"width": "807px"})
+assert-css: (".item-info", {"width": "757px"})
 assert-css: (".item-info .stab", {"width": "341px"})
diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml
new file mode 100644
index 00000000000..acde1123925
--- /dev/null
+++ b/src/test/rustdoc-gui/mobile.goml
@@ -0,0 +1,17 @@
+// Test various properties of the mobile UI
+goto: file://|DOC_PATH|/staged_api/struct.Foo.html
+size: (400, 600)
+
+// The out-of-band info (source, stable version, collapse) should be below the
+// h1 when the screen gets narrow enough.
+assert-css: (".main-heading", {
+  "display": "flex",
+  "flex-direction": "column"
+})
+
+// Note: We can't use assert-text here because the 'Since' is set by CSS and
+// is therefore not part of the DOM.
+assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
+
+size: (1000, 1000)
+assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
index ea94e5640fb..3162a067d21 100644
--- a/src/test/rustdoc-gui/search-result-display.goml
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -5,7 +5,7 @@ write: (".search-input", "test")
 wait-for: "#titles"
 // The width is returned by "getComputedStyle" which returns the exact number instead of the
 // CSS rule which is "50%"...
-assert-css: (".search-results div.desc", {"width": "320px"})
+assert-css: (".search-results div.desc", {"width": "295px"})
 size: (600, 100)
 // As counter-intuitive as it may seem, in this width, the width is "100%", which is why
 // when computed it's larger.
diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml
index 7138f916675..680822b6ecb 100644
--- a/src/test/rustdoc-gui/sidebar-mobile.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile.goml
@@ -4,17 +4,34 @@
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 // Switching to "mobile view" by reducing the width to 600px.
 size: (600, 600)
-assert-css: (".sidebar-elems", {"display": "block", "left": "-246px"})
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 // Opening the sidebar menu.
-click: ".sidebar-menu"
-assert-css: (".sidebar-elems", {"display": "block", "left": "0px"})
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"display": "block", "left": "0px"})
 // Closing the sidebar menu.
-click: ".sidebar-menu"
-assert-css: (".sidebar-elems", {"display": "block", "left": "-246px"})
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 // Force the sidebar open by focusing a link inside it.
 // This makes it easier for keyboard users to get to it.
 focus: ".sidebar-title a"
-assert-css: (".sidebar-elems", {"display": "block", "left": "0px"})
+assert-css: (".sidebar", {"display": "block", "left": "0px"})
 // When we tab out of the sidebar, close it.
 focus: ".search-input"
-assert-css: (".sidebar-elems", {"display": "block", "left": "-246px"})
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"left": "0px"})
+
+// Click elsewhere.
+click: "body"
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Check that the topbar is visible
+assert-property: (".mobile-topbar", {"clientHeight": "45"})
+
+// Check that clicking an element from the sidebar scrolls to the right place
+// so the target is not obscured by the topbar.
+click: ".sidebar-menu-toggle"
+click: ".sidebar-links a"
+assert-position: ("#method\.must_use", {"y": 45})
diff --git a/src/test/rustdoc-gui/sidebar-source-code.goml b/src/test/rustdoc-gui/sidebar-source-code.goml
index 98f4fdf4233..1c5eb9239ba 100644
--- a/src/test/rustdoc-gui/sidebar-source-code.goml
+++ b/src/test/rustdoc-gui/sidebar-source-code.goml
@@ -10,6 +10,7 @@ click: (10, 10)
 // We wait for the sidebar to be expanded (there is a 0.5s animation).
 wait-for: 600
 assert-css: ("nav.sidebar.expanded", {"width": "300px"})
+assert-css: ("nav.sidebar.expanded a", {"font-size": "14.4px"})
 // We collapse the sidebar.
 click: (10, 10)
 // We wait for the sidebar to be collapsed (there is a 0.5s animation).
@@ -30,3 +31,6 @@ click: (10, 10)
 // We ensure that the class has been removed.
 assert-false: "nav.sidebar.expanded"
 assert: "nav.sidebar"
+
+// Check that the topbar is not visible
+assert-property: (".mobile-topbar", {"offsetParent": "null"})
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
index 9289244f6f8..a1175525858 100644
--- a/src/test/rustdoc-gui/sidebar.goml
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -1,8 +1,14 @@
 goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true
+local-storage: {"rustdoc-theme": "light"}
+// We reload the page so the local storage settings are being used.
+reload:
+
 assert-text: (".sidebar > .location", "Crate test_docs")
 // In modules, we only have one "location" element.
 assert-count: (".sidebar .location", 1)
-assert-text: (".sidebar-elems > #all-types", "See all test_docs's items")
+assert-text: ("#all-types", "All Items")
+assert-css: ("#all-types", {"color": "rgb(56, 115, 173)"})
 // We check that we have the crates list and that the "current" on is "test_docs".
 assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
 // And we're also supposed to have the list of items in the current module.
@@ -24,13 +30,14 @@ assert-count: (".sidebar .location", 2)
 assert-false: ".sidebar-elems > .crate"
 
 click: ".sidebar-links a"
-assert-property: ("html", {"scrollTop": "389"})
+assert-property-false: ("html", {"scrollTop": "0"})
 
-click: ".sidebar h2.location"
+click: ".sidebar h2.location a"
 assert-property: ("html", {"scrollTop": "0"})
 
 // We now go back to the crate page to click on the "lib2" crate link.
 goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(56, 115, 173)"})
 click: ".sidebar-elems .crate > ul > li:first-child > a"
 
 // PAGE: lib2/index.html
@@ -51,8 +58,7 @@ click: "#functions + .item-table .item-left > a"
 // In items containing no items (like functions or constants) and in modules, we have one
 // "location" elements.
 assert-count: (".sidebar .location", 1)
-// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space.
-assert-text: (".sidebar .sidebar-elems .location", "Other items inlib2")
+assert-text: (".sidebar .sidebar-elems .location", "In lib2")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems > .crate"
 
diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.lock b/src/test/rustdoc-gui/src/staged_api/Cargo.lock
new file mode 100644
index 00000000000..6e8eba56c1e
--- /dev/null
+++ b/src/test/rustdoc-gui/src/staged_api/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "staged_api"
+version = "0.1.0"
diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.toml b/src/test/rustdoc-gui/src/staged_api/Cargo.toml
new file mode 100644
index 00000000000..117c4134e34
--- /dev/null
+++ b/src/test/rustdoc-gui/src/staged_api/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "staged_api"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+path = "lib.rs"
+
+[features]
+default = ["some_feature"]
+some_feature = []
diff --git a/src/test/rustdoc-gui/src/staged_api/lib.rs b/src/test/rustdoc-gui/src/staged_api/lib.rs
new file mode 100644
index 00000000000..0cb460f03f7
--- /dev/null
+++ b/src/test/rustdoc-gui/src/staged_api/lib.rs
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![stable(feature = "some_feature", since = "1.3.5")]
+
+#[stable(feature = "some_feature", since = "1.3.5")]
+pub struct Foo {}
+
+impl Foo {
+    #[stable(feature = "some_feature", since = "1.3.5")]
+    pub fn bar() {}
+}
diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml
index 6e0ad8e0fa7..e7a75b43c5a 100644
--- a/src/test/rustdoc-gui/toggle-docs-mobile.goml
+++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml
@@ -1,12 +1,12 @@
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 size: (433, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 240) // This is the position of the top doc comment toggle
+click: (4, 270) // This is the position of the top doc comment toggle
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 240)
+click: (4, 270)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 240)
+click: (3, 270)
 assert-attribute: (".top-doc", {"open": ""})
 
 // Assert the position of the toggle on the top doc block.
@@ -22,10 +22,10 @@ assert-position: (
 // Now we do the same but with a little bigger width
 size: (600, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 240) // New Y position since all search elements are back on one line.
+click: (4, 270) // New Y position since all search elements are back on one line.
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 240)
+click: (4, 270)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 240)
+click: (3, 270)
 assert-attribute: (".top-doc", {"open": ""})
diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml
index bb24d0ce792..21874f786f1 100644
--- a/src/test/rustdoc-gui/type-declation-overflow.goml
+++ b/src/test/rustdoc-gui/type-declation-overflow.goml
@@ -11,7 +11,7 @@ assert-property: (".item-decl pre", {"scrollWidth": "1324"})
 goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html
 assert-property: ("body", {"scrollWidth": "1100"})
 // We now check that the section width hasn't grown because of it.
-assert-property: ("#main-content", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "825"})
 // And now checking that it has scrollable content.
 assert-property: (".item-decl pre", {"scrollWidth": "1103"})
 
@@ -20,6 +20,13 @@ assert-property: (".item-decl pre", {"scrollWidth": "1103"})
 goto: file://|DOC_PATH|/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html
 assert-property: ("body", {"scrollWidth": "1100"})
 // We now check that the section width hasn't grown because of it.
-assert-property: ("#main-content", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "825"})
 // And now checking that it has scrollable content.
 assert-property: (".item-decl pre", {"scrollWidth": "950"})
+
+// On mobile:
+size: (600, 600)
+goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
+assert-property: (".mobile-topbar .location", {"scrollWidth": "504"})
+assert-property: (".mobile-topbar .location", {"clientWidth": "504"})
+assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs
index 246e6a09007..fcd92887c0b 100644
--- a/src/test/rustdoc-json/enums/variant_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_struct.rs
@@ -2,8 +2,8 @@
 // @has - "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
 pub enum EnumStruct {
     // @has - "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
-    // @has - "$.index[*][?(@.name=='x')]"
-    // @has - "$.index[*][?(@.name=='y')]"
+    // @has - "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+    // @has - "$.index[*][?(@.name=='y')].kind" \"struct_field\"
     VariantS {
         x: u32,
         y: String,
diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
index d948dc552cd..ac3e72e2905 100644
--- a/src/test/rustdoc-json/enums/variant_tuple_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
@@ -2,5 +2,7 @@
 // @has - "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
 pub enum EnumTupleStruct {
     // @has - "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
+    // @has - "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+    // @has - "$.index[*][?(@.name=='1')].kind" \"struct_field\"
     VariantA(u32, String),
 }
diff --git a/src/test/rustdoc-json/impls/blanket_with_local.rs b/src/test/rustdoc-json/impls/blanket_with_local.rs
new file mode 100644
index 00000000000..963ea2fe5ae
--- /dev/null
+++ b/src/test/rustdoc-json/impls/blanket_with_local.rs
@@ -0,0 +1,14 @@
+// Test for the ICE in rust/83718
+// A blanket impl plus a local type together shouldn't result in mismatched ID issues
+
+// @has blanket_with_local.json "$.index[*][?(@.name=='Load')]"
+pub trait Load {
+    fn load() {}
+}
+
+impl<P> Load for P {
+    fn load() {}
+}
+
+// @has - "$.index[*][?(@.name=='Wrapper')]"
+pub struct Wrapper {}
diff --git a/src/test/rustdoc/cap-lints.rs b/src/test/rustdoc/cap-lints.rs
index 15910e1e900..08a35339680 100644
--- a/src/test/rustdoc/cap-lints.rs
+++ b/src/test/rustdoc/cap-lints.rs
@@ -3,7 +3,7 @@
 // therefore should not concern itself with the lints.
 #[deny(warnings)]
 
-// @has cap_lints/struct.Foo.html //* 'Struct Foo'
+// @has cap_lints/struct.Foo.html //* 'Foo'
 pub struct Foo {
     field: i32,
 }
diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs
index fb8ea7e33c2..b8e101038f8 100644
--- a/src/test/rustdoc/const-display.rs
+++ b/src/test/rustdoc/const-display.rs
@@ -67,3 +67,20 @@ impl Foo {
     #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
     pub const fn stable_impl() -> u32 { 42 }
 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Bar;
+
+impl Bar {
+    // Do not show non-const stabilities that are the same as the enclosing item.
+    // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.2.0$'
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
+    pub const fn stable_impl() -> u32 { 42 }
+
+    // Show const-stability even for unstable functions.
+    // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$'
+    #[unstable(feature = "foo2", issue = "none")]
+    #[rustc_const_stable(feature = "rust1", since = "1.3.0")]
+    pub const fn const_stable_unstable() -> u32 { 42 }
+}
diff --git a/src/test/rustdoc/crate-version-escape.rs b/src/test/rustdoc/crate-version-escape.rs
index 2f91eea339b..8413709f15e 100644
--- a/src/test/rustdoc/crate-version-escape.rs
+++ b/src/test/rustdoc/crate-version-escape.rs
@@ -2,5 +2,4 @@
 
 #![crate_name = "foo"]
 
-// @has 'foo/index.html' '//div[@class="block version"]/p' 'Version <script>alert("hi")</script>'
-// @has 'foo/all.html' '//div[@class="block version"]/p' 'Version <script>alert("hi")</script>'
+// @has 'foo/index.html' '//li[@class="version"]' 'Version <script>alert("hi")</script>'
diff --git a/src/test/rustdoc/crate-version.rs b/src/test/rustdoc/crate-version.rs
index 893af5c6133..2592c98530f 100644
--- a/src/test/rustdoc/crate-version.rs
+++ b/src/test/rustdoc/crate-version.rs
@@ -1,3 +1,3 @@
 // compile-flags: --crate-version=1.3.37
 
-// @has 'crate_version/index.html' '//div[@class="block version"]/p' 'Version 1.3.37'
+// @has 'crate_version/index.html' '//*[@class="version"]' 'Version 1.3.37'
diff --git a/src/test/rustdoc/deref-const-fn.rs b/src/test/rustdoc/deref-const-fn.rs
index ca51f3c7b5a..8ecca6d12d2 100644
--- a/src/test/rustdoc/deref-const-fn.rs
+++ b/src/test/rustdoc/deref-const-fn.rs
@@ -13,7 +13,7 @@ pub struct Bar;
 
 impl Bar {
     // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize'
-    // @has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0 (const: 1.0.0)'
+    // @has - '//*[@id="method.len"]//span[@class="since"]' 'const: 1.0.0'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
     pub const fn len(&self) -> usize { 0 }
diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs
index fcdd8354569..57dd0529535 100644
--- a/src/test/rustdoc/doc-auto-cfg.rs
+++ b/src/test/rustdoc/doc-auto-cfg.rs
@@ -3,6 +3,12 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.foo.html
-// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test'
-#[cfg(not(test))]
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-doctest'
+#[cfg(not(doctest))]
 pub fn foo() {}
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'test'
+#[cfg(any(test, doc))]
+pub fn bar() {}
diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs
index 424fa6d6a91..636957fe998 100644
--- a/src/test/rustdoc/doc-cfg-hide.rs
+++ b/src/test/rustdoc/doc-cfg-hide.rs
@@ -26,7 +26,7 @@ pub struct Hyperdulia;
 
 // @has 'oud/struct.Oystercatcher.html'
 // @count   - '//*[@class="stab portability"]' 1
-// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher'
+// @matches - '//*[@class="stab portability"]' 'crate feature oystercatcher only'
 // compile-flags:--cfg feature="oystercatcher"
 #[cfg(all(feature = "solecism", feature = "oystercatcher"))]
 pub struct Oystercatcher;
diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html
new file mode 100644
index 00000000000..22b0b5dc47e
--- /dev/null
+++ b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html
@@ -0,0 +1,2 @@
+<div class="docblock"><p>a</p>
+</div>
\ No newline at end of file
diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.rs b/src/test/rustdoc/strip-block-doc-comments-stars.rs
new file mode 100644
index 00000000000..ed2297b4fac
--- /dev/null
+++ b/src/test/rustdoc/strip-block-doc-comments-stars.rs
@@ -0,0 +1,11 @@
+#![crate_name = "foo"]
+
+// The goal of this test is to answer that it won't be generated as a list because
+// block doc comments can have their lines starting with a star.
+
+// @has foo/fn.foo.html
+// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]'
+/**
+ *     a
+ */
+pub fn foo() {}
diff --git a/src/test/rustdoc/titles.rs b/src/test/rustdoc/titles.rs
index 016ec7bfaa3..69e8b856b0a 100644
--- a/src/test/rustdoc/titles.rs
+++ b/src/test/rustdoc/titles.rs
@@ -1,10 +1,11 @@
 #![crate_name = "foo"]
-
 #![feature(rustdoc_internals)]
 
 // @matches 'foo/index.html' '//h1' 'Crate foo'
+// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo'
 
 // @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
+// @matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod'
 pub mod foo_mod {
     pub struct __Thing {}
 }
@@ -18,15 +19,19 @@ extern "C" {
 pub fn foo_fn() {}
 
 // @matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait'
+// @matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait'
 pub trait FooTrait {}
 
 // @matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct'
+// @matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct'
 pub struct FooStruct;
 
 // @matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum'
+// @matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum'
 pub enum FooEnum {}
 
 // @matches 'foo/type.FooType.html' '//h1' 'Type Definition foo::FooType'
+// @matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType'
 pub type FooType = FooStruct;
 
 // @matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro'
diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs
index 1fb28ee9970..4ecd62cded2 100644
--- a/src/test/rustdoc/typedef.rs
+++ b/src/test/rustdoc/typedef.rs
@@ -12,7 +12,7 @@ impl MyStruct {
 // @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyAlias'
 // @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyTrait for MyAlias'
 // @has - 'Alias docstring'
-// @has - '//*[@class="sidebar"]//*[@class="location"]' 'Type Definition MyAlias'
+// @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
 // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
 // @has - '//*[@class="sidebar"]//a[@href="#trait-implementations"]' 'Trait Implementations'
 /// Alias docstring
diff --git a/src/test/ui/associated-consts/assoc-const.rs b/src/test/ui/associated-consts/assoc-const.rs
new file mode 100644
index 00000000000..cd4b42f9f84
--- /dev/null
+++ b/src/test/ui/associated-consts/assoc-const.rs
@@ -0,0 +1,21 @@
+#![feature(associated_const_equality)]
+
+pub trait Foo {
+  const N: usize;
+}
+
+pub struct Bar;
+
+impl Foo for Bar {
+  const N: usize = 3;
+}
+
+const TEST:usize = 3;
+
+
+fn foo<F: Foo<N=3>>() {}
+//~^ ERROR associated const equality is incomplete
+fn bar<F: Foo<N={TEST}>>() {}
+//~^ ERROR associated const equality is incomplete
+
+fn main() {}
diff --git a/src/test/ui/associated-consts/assoc-const.stderr b/src/test/ui/associated-consts/assoc-const.stderr
new file mode 100644
index 00000000000..ccaa6fa8ee8
--- /dev/null
+++ b/src/test/ui/associated-consts/assoc-const.stderr
@@ -0,0 +1,14 @@
+error: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:16:15
+   |
+LL | fn foo<F: Foo<N=3>>() {}
+   |               ^^^ cannot yet relate associated const
+
+error: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:18:15
+   |
+LL | fn bar<F: Foo<N={TEST}>>() {}
+   |               ^^^^^^^^ cannot yet relate associated const
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
index 845941200fc..c5453b67ef5 100644
--- a/src/test/ui/async-await/async-fn-nonsend.rs
+++ b/src/test/ui/async-await/async-fn-nonsend.rs
@@ -18,7 +18,7 @@ async fn fut() {}
 async fn fut_arg<T>(_: T) {}
 
 async fn local_dropped_before_await() {
-    // FIXME: it'd be nice for this to be allowed in a `Send` `async fn`
+    // this is okay now because of the drop
     let x = non_send();
     drop(x);
     fut().await;
@@ -35,21 +35,40 @@ async fn non_send_temporary_in_match() {
     }
 }
 
+fn get_formatter() -> std::fmt::Formatter<'static> {
+    panic!()
+}
+
 async fn non_sync_with_method_call() {
-    // FIXME: it'd be nice for this to work.
+    let f: &mut std::fmt::Formatter = &mut get_formatter();
+    // It would by nice for this to work.
+    if non_sync().fmt(f).unwrap() == () {
+        fut().await;
+    }
+}
+
+async fn non_sync_with_method_call_panic() {
     let f: &mut std::fmt::Formatter = panic!();
     if non_sync().fmt(f).unwrap() == () {
         fut().await;
     }
 }
 
+async fn non_sync_with_method_call_infinite_loop() {
+    let f: &mut std::fmt::Formatter = loop {};
+    if non_sync().fmt(f).unwrap() == () {
+        fut().await;
+    }
+}
+
 fn assert_send(_: impl Send) {}
 
 pub fn pass_assert() {
     assert_send(local_dropped_before_await());
-    //~^ ERROR future cannot be sent between threads safely
     assert_send(non_send_temporary_in_match());
     //~^ ERROR future cannot be sent between threads safely
     assert_send(non_sync_with_method_call());
     //~^ ERROR future cannot be sent between threads safely
+    assert_send(non_sync_with_method_call_panic());
+    assert_send(non_sync_with_method_call_infinite_loop());
 }
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index bff28208573..40ad46b4862 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -1,28 +1,5 @@
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:49:17
-   |
-LL |     assert_send(local_dropped_before_await());
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
-   |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
-note: future is not `Send` as this value is used across an await
-  --> $DIR/async-fn-nonsend.rs:24:10
-   |
-LL |     let x = non_send();
-   |         - has type `impl Debug` which is not `Send`
-LL |     drop(x);
-LL |     fut().await;
-   |          ^^^^^^ await occurs here, with `x` maybe used later
-LL | }
-   | - `x` is later dropped here
-note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:46:24
-   |
-LL | fn assert_send(_: impl Send) {}
-   |                        ^^^^ required by this bound in `assert_send`
-
-error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:51:17
+  --> $DIR/async-fn-nonsend.rs:68:17
    |
 LL |     assert_send(non_send_temporary_in_match());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
@@ -32,41 +9,41 @@ note: future is not `Send` as this value is used across an await
   --> $DIR/async-fn-nonsend.rs:33:25
    |
 LL |     match Some(non_send()) {
-   |                ---------- has type `impl Debug` which is not `Send`
+   |           ---------------- has type `Option<impl Debug>` which is not `Send`
 LL |         Some(_) => fut().await,
-   |                         ^^^^^^ await occurs here, with `non_send()` maybe used later
+   |                         ^^^^^^ await occurs here, with `Some(non_send())` maybe used later
 ...
 LL | }
-   | - `non_send()` is later dropped here
+   | - `Some(non_send())` is later dropped here
 note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:46:24
+  --> $DIR/async-fn-nonsend.rs:64:24
    |
 LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
 
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:53:17
+  --> $DIR/async-fn-nonsend.rs:70:17
    |
 LL |     assert_send(non_sync_with_method_call());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
    = help: the trait `Send` is not implemented for `dyn std::fmt::Write`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/async-fn-nonsend.rs:42:14
+  --> $DIR/async-fn-nonsend.rs:46:14
    |
-LL |     let f: &mut std::fmt::Formatter = panic!();
-   |         - has type `&mut Formatter<'_>` which is not `Send`
-LL |     if non_sync().fmt(f).unwrap() == () {
+LL |     let f: &mut std::fmt::Formatter = &mut get_formatter();
+   |                                            --------------- has type `Formatter<'_>` which is not `Send`
+...
 LL |         fut().await;
-   |              ^^^^^^ await occurs here, with `f` maybe used later
+   |              ^^^^^^ await occurs here, with `get_formatter()` maybe used later
 LL |     }
 LL | }
-   | - `f` is later dropped here
+   | - `get_formatter()` is later dropped here
 note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:46:24
+  --> $DIR/async-fn-nonsend.rs:64:24
    |
 LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/async-await/issue-76547.stderr b/src/test/ui/async-await/issue-76547.stderr
index 9bfb0f28028..ac5f99970c8 100644
--- a/src/test/ui/async-await/issue-76547.stderr
+++ b/src/test/ui/async-await/issue-76547.stderr
@@ -2,23 +2,17 @@ error[E0623]: lifetime mismatch
   --> $DIR/issue-76547.rs:20:13
    |
 LL | async fn fut(bufs: &mut [&mut [u8]]) {
-   |                          ---------   -
-   |                          |           |
-   |                          |           this `async fn` implicitly returns an `impl Future<Output = ()>`
-   |                          this parameter and the returned future are declared with different lifetimes...
+   |                    ---------------- these two types are declared with different lifetimes...
 LL |     ListFut(bufs).await
-   |             ^^^^ ...but data from `bufs` is held across an await point here
+   |             ^^^^ ...but data from `bufs` flows into `bufs` here
 
 error[E0623]: lifetime mismatch
   --> $DIR/issue-76547.rs:34:14
    |
 LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
-   |                           ---------      ---
-   |                           |              |
-   |                           |              this `async fn` implicitly returns an `impl Future<Output = i32>`
-   |                           this parameter and the returned future are declared with different lifetimes...
+   |                     ---------------- these two types are declared with different lifetimes...
 LL |     ListFut2(bufs).await
-   |              ^^^^ ...but data from `bufs` is held across an await point here
+   |              ^^^^ ...but data from `bufs` flows into `bufs` here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/async-await/issues/issue-63388-1.stderr b/src/test/ui/async-await/issues/issue-63388-1.stderr
index ac29cca9d3f..8f602a1492a 100644
--- a/src/test/ui/async-await/issues/issue-63388-1.stderr
+++ b/src/test/ui/async-await/issues/issue-63388-1.stderr
@@ -2,14 +2,12 @@ error[E0623]: lifetime mismatch
   --> $DIR/issue-63388-1.rs:14:9
    |
 LL |         &'a self, foo: &dyn Foo
-   |         -------- this parameter and the returned future are declared with different lifetimes...
+   |                        -------- this parameter and the return type are declared with different lifetimes...
 LL |     ) -> &dyn Foo
    |          --------
-   |          |
-   |          this `async fn` implicitly returns an `impl Future<Output = &dyn Foo>`
 LL |     {
 LL |         foo
-   |         ^^^ ...but data from `foo` is held across an await point here
+   |         ^^^ ...but data from `foo` is returned here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
index 464f283095d..149692a2c69 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
@@ -4,9 +4,8 @@ error[E0623]: lifetime mismatch
 LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
    |                                                      ------     ^^^^^^^^^^^^^^^^^^^
    |                                                      |          |
-   |                                                      |          ...but data from `a` is held across an await point here
-   |                                                      |          this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a> + 'b>`
-   |                                                      this parameter and the returned future are declared with different lifetimes...
+   |                                                      |          ...but data from `a` is returned here
+   |                                                      this parameter and the return type are declared with different lifetimes...
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/ret-impl-trait-one.rs:16:65
diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.rs b/src/test/ui/async-await/partial-drop-partial-reinit.rs
new file mode 100644
index 00000000000..73f0ca8153c
--- /dev/null
+++ b/src/test/ui/async-await/partial-drop-partial-reinit.rs
@@ -0,0 +1,29 @@
+// edition:2021
+#![feature(negative_impls)]
+#![allow(unused)]
+
+fn main() {
+    gimme_send(foo());
+    //~^ ERROR cannot be sent between threads safely
+}
+
+fn gimme_send<T: Send>(t: T) {
+    drop(t);
+}
+
+struct NotSend {}
+
+impl Drop for NotSend {
+    fn drop(&mut self) {}
+}
+
+impl !Send for NotSend {}
+
+async fn foo() {
+    let mut x = (NotSend {},);
+    drop(x.0);
+    x.0 = NotSend {};
+    bar().await;
+}
+
+async fn bar() {}
diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr
new file mode 100644
index 00000000000..2097642eb24
--- /dev/null
+++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr
@@ -0,0 +1,27 @@
+error[E0277]: `NotSend` cannot be sent between threads safely
+  --> $DIR/partial-drop-partial-reinit.rs:6:16
+   |
+LL |     gimme_send(foo());
+   |     ---------- ^^^^^ `NotSend` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+...
+LL | async fn foo() {
+   |                - within this `impl Future<Output = ()>`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
+   = note: required because it appears within the type `(NotSend,)`
+   = note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
+   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
+   = note: required because it appears within the type `impl Future<Output = [async output]>`
+   = note: required because it appears within the type `impl Future<Output = ()>`
+note: required by a bound in `gimme_send`
+  --> $DIR/partial-drop-partial-reinit.rs:10:18
+   |
+LL | fn gimme_send<T: Send>(t: T) {
+   |                  ^^^^ required by this bound in `gimme_send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index 85d868c2703..d313691b388 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -10,20 +10,12 @@ async fn foo() {
     //~^ ERROR type inside `async fn` body must be known in this context
     //~| ERROR type inside `async fn` body must be known in this context
     //~| ERROR type inside `async fn` body must be known in this context
-    //~| ERROR type inside `async fn` body must be known in this context
-    //~| ERROR type inside `async fn` body must be known in this context
-    //~| NOTE cannot infer type for type parameter `T`
-    //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE in this expansion of desugaring of `await`
-    //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index 8c0ecb8785d..d19a3226ef9 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -34,30 +34,6 @@ note: the type is part of the `async fn` body because of this `await`
 LL |     bar().await;
    |          ^^^^^^
 
-error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/unresolved_type_param.rs:9:5
-   |
-LL |     bar().await;
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
-   |
-note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/unresolved_type_param.rs:9:10
-   |
-LL |     bar().await;
-   |          ^^^^^^
-
-error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/unresolved_type_param.rs:9:5
-   |
-LL |     bar().await;
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
-   |
-note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/unresolved_type_param.rs:9:10
-   |
-LL |     bar().await;
-   |          ^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0698`.
diff --git a/src/test/ui/autoref-autoderef/deref-into-array.rs b/src/test/ui/autoref-autoderef/deref-into-array.rs
new file mode 100644
index 00000000000..855a82d2f9c
--- /dev/null
+++ b/src/test/ui/autoref-autoderef/deref-into-array.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+struct Test<T>([T; 1]);
+
+impl<T> std::ops::Deref for Test<T> {
+    type Target = [T; 1];
+
+    fn deref(&self) -> &[T; 1] {
+        &self.0
+    }
+}
+
+fn main() {
+    let out = Test([(); 1]);
+    let blah = out.len();
+    println!("{}", blah);
+}
diff --git a/src/test/ui/const-generics/deref-into-array-generic.rs b/src/test/ui/const-generics/deref-into-array-generic.rs
new file mode 100644
index 00000000000..7d75af12bdf
--- /dev/null
+++ b/src/test/ui/const-generics/deref-into-array-generic.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+struct Test<T, const N: usize>([T; N]);
+
+impl<T: Copy + Default, const N: usize> Default for Test<T, N> {
+    fn default() -> Self {
+        Self([T::default(); N])
+    }
+}
+
+impl<T, const N: usize> std::ops::Deref for Test<T, N> {
+    type Target = [T; N];
+
+    fn deref(&self) -> &[T; N] {
+        &self.0
+    }
+}
+
+fn test() -> Test<u64, 16> {
+    let test = Test::default();
+    println!("{}", test.len());
+    test
+}
+
+fn main() {
+    test();
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs
deleted file mode 100644
index 56b88a426a1..00000000000
--- a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// To avoid having to `or` gate `_` as an expr.
-#![feature(generic_arg_infer)]
-
-fn foo() -> [u8; _] {
-    //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics
-    // FIXME(generic_arg_infer): this error message should say in the return type or sth like that.
-    [0; 3]
-}
-
-fn main() {
-    foo();
-}
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr
deleted file mode 100644
index eaa12b4192d..00000000000
--- a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics
-  --> $DIR/array-in-sig.rs:4:18
-   |
-LL | fn foo() -> [u8; _] {
-   |                  ^ not allowed in type signatures
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/const-generics/generic_arg_infer/in-signature.rs b/src/test/ui/const-generics/generic_arg_infer/in-signature.rs
new file mode 100644
index 00000000000..1f60b224241
--- /dev/null
+++ b/src/test/ui/const-generics/generic_arg_infer/in-signature.rs
@@ -0,0 +1,61 @@
+#![crate_type = "rlib"]
+#![feature(generic_arg_infer)]
+
+struct Foo<const N: usize>;
+struct Bar<T, const N: usize>(T);
+
+fn arr_fn() -> [u8; _] {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    [0; 3]
+}
+
+fn ty_fn() -> Bar<i32, _> {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    Bar::<i32, 3>(0)
+}
+
+fn ty_fn_mixed() -> Bar<_, _> {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    Bar::<i32, 3>(0)
+}
+
+const ARR_CT: [u8; _] = [0; 3];
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+static ARR_STATIC: [u8; _] = [0; 3];
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
+const TY_CT: Bar<i32, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+static TY_STATIC: Bar<i32, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
+const TY_CT_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+static TY_STATIC_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
+trait ArrAssocConst {
+    const ARR: [u8; _];
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+}
+trait TyAssocConst {
+    const ARR: Bar<i32, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+}
+trait TyAssocConstMixed {
+    const ARR: Bar<_, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+}
+
+trait AssocTy {
+    type Assoc;
+}
+impl AssocTy for i8 {
+    type Assoc = [u8; _];
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+}
+impl AssocTy for i16 {
+    type Assoc = Bar<i32, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+}
+impl AssocTy for i32 {
+    type Assoc = Bar<_, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr
new file mode 100644
index 00000000000..7581cf4120e
--- /dev/null
+++ b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr
@@ -0,0 +1,119 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/in-signature.rs:7:21
+   |
+LL | fn arr_fn() -> [u8; _] {
+   |                -----^-
+   |                |    |
+   |                |    not allowed in type signatures
+   |                help: replace with the correct return type: `[u8; 3]`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/in-signature.rs:12:24
+   |
+LL | fn ty_fn() -> Bar<i32, _> {
+   |               ---------^-
+   |               |        |
+   |               |        not allowed in type signatures
+   |               help: replace with the correct return type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/in-signature.rs:17:25
+   |
+LL | fn ty_fn_mixed() -> Bar<_, _> {
+   |                     ----^--^-
+   |                     |   |  |
+   |                     |   |  not allowed in type signatures
+   |                     |   not allowed in type signatures
+   |                     help: replace with the correct return type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:22:15
+   |
+LL | const ARR_CT: [u8; _] = [0; 3];
+   |               ^^^^^^^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
+  --> $DIR/in-signature.rs:24:20
+   |
+LL | static ARR_STATIC: [u8; _] = [0; 3];
+   |                    ^^^^^^^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:26:14
+   |
+LL | const TY_CT: Bar<i32, _> = Bar::<i32, 3>(0);
+   |              ^^^^^^^^^^^
+   |              |
+   |              not allowed in type signatures
+   |              help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
+  --> $DIR/in-signature.rs:28:19
+   |
+LL | static TY_STATIC: Bar<i32, _> = Bar::<i32, 3>(0);
+   |                   ^^^^^^^^^^^
+   |                   |
+   |                   not allowed in type signatures
+   |                   help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:30:20
+   |
+LL | const TY_CT_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+   |                    ^^^^^^^^^
+   |                    |
+   |                    not allowed in type signatures
+   |                    help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
+  --> $DIR/in-signature.rs:32:25
+   |
+LL | static TY_STATIC_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+   |                         ^^^^^^^^^
+   |                         |
+   |                         not allowed in type signatures
+   |                         help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:35:21
+   |
+LL |     const ARR: [u8; _];
+   |                     ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:39:25
+   |
+LL |     const ARR: Bar<i32, _>;
+   |                         ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:43:20
+   |
+LL |     const ARR: Bar<_, _>;
+   |                    ^  ^ not allowed in type signatures
+   |                    |
+   |                    not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+  --> $DIR/in-signature.rs:51:23
+   |
+LL |     type Assoc = [u8; _];
+   |                       ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+  --> $DIR/in-signature.rs:55:27
+   |
+LL |     type Assoc = Bar<i32, _>;
+   |                           ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+  --> $DIR/in-signature.rs:59:22
+   |
+LL |     type Assoc = Bar<_, _>;
+   |                      ^  ^ not allowed in type signatures
+   |                      |
+   |                      not allowed in type signatures
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/const-generics/issues/issue-92186.rs b/src/test/ui/const-generics/issues/issue-92186.rs
new file mode 100644
index 00000000000..9ced4667d24
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-92186.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub struct Foo<const N: usize>;
+pub trait Bar<T> {}
+
+impl<T> Bar<T> for Foo<{ 1 }> {}
+impl<T> Bar<T> for Foo<{ 2 }> {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
index 19e0f38d320..b126b24853f 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
@@ -7,8 +7,9 @@ struct Bar;
 const T: usize = 42;
 
 impl Foo<N = 3> for Bar {
-//~^ ERROR cannot constrain an associated constant to a value
+//~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
 //~| ERROR associated type bindings are not allowed here
+//~| ERROR associated const equality is incomplete
     fn do_x(&self) -> [u8; 3] {
         [0u8; 3]
     }
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
index bbca92ad63a..59ba054aa11 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
@@ -1,11 +1,27 @@
-error: cannot constrain an associated constant to a value
+error[E0658]: associated const equality is incomplete
   --> $DIR/issue-89013-no-kw.rs:9:10
    |
 LL | impl Foo<N = 3> for Bar {
-   |          -^^^-
-   |          |   |
-   |          |   ...cannot be constrained to this value
-   |          this associated constant...
+   |          ^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/issue-89013-no-kw.rs:9:6
+   |
+LL | impl Foo<N = 3> for Bar {
+   |      ^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `N`
+  --> $DIR/issue-89013-no-kw.rs:1:7
+   |
+LL | trait Foo<const N: usize> {
+   |       ^^^       -
+help: add missing generic argument
+   |
+LL | impl Foo<N, N = 3> for Bar {
+   |          ++
 
 error[E0229]: associated type bindings are not allowed here
   --> $DIR/issue-89013-no-kw.rs:9:10
@@ -13,6 +29,7 @@ error[E0229]: associated type bindings are not allowed here
 LL | impl Foo<N = 3> for Bar {
    |          ^^^^^ associated type not allowed here
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0229`.
+Some errors have detailed explanations: E0107, E0229, E0658.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
index ca1158a2f6d..9431779faf8 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
@@ -8,8 +8,9 @@ const T: usize = 42;
 
 impl Foo<N = const 3> for Bar {
 //~^ ERROR expected lifetime, type, or constant, found keyword `const`
-//~| ERROR cannot constrain an associated constant to a value
+//~| ERROR this trait takes 1 generic
 //~| ERROR associated type bindings are not allowed here
+//~| ERROR associated const equality is incomplete
     fn do_x(&self) -> [u8; 3] {
         [0u8; 3]
     }
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
index 85379d3f06e..9d473992670 100644
--- a/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
@@ -10,14 +10,30 @@ LL - impl Foo<N = const 3> for Bar {
 LL + impl Foo<N = 3> for Bar {
    | 
 
-error: cannot constrain an associated constant to a value
+error[E0658]: associated const equality is incomplete
   --> $DIR/issue-89013.rs:9:10
    |
 LL | impl Foo<N = const 3> for Bar {
-   |          -^^^^^^^^^-
-   |          |         |
-   |          |         ...cannot be constrained to this value
-   |          this associated constant...
+   |          ^^^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/issue-89013.rs:9:6
+   |
+LL | impl Foo<N = const 3> for Bar {
+   |      ^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `N`
+  --> $DIR/issue-89013.rs:1:7
+   |
+LL | trait Foo<const N: usize> {
+   |       ^^^       -
+help: add missing generic argument
+   |
+LL | impl Foo<N, N = const 3> for Bar {
+   |          ++
 
 error[E0229]: associated type bindings are not allowed here
   --> $DIR/issue-89013.rs:9:10
@@ -25,6 +41,7 @@ error[E0229]: associated type bindings are not allowed here
 LL | impl Foo<N = const 3> for Bar {
    |          ^^^^^^^^^^^ associated type not allowed here
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0229`.
+Some errors have detailed explanations: E0107, E0229, E0658.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.full.stderr b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr
index 565c9ba1ff1..4d6b752867f 100644
--- a/src/test/ui/const-generics/types-mismatch-const-args.full.stderr
+++ b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr
@@ -15,9 +15,20 @@ LL |     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data
    |            |
    |            expected due to this
    |
-   = note: expected struct `A<'a, u16, {2u32}, {3u32}>`
-              found struct `A<'b, u32, {2u32}, {3u32}>`
+   = note: expected struct `A<'a, u16, _, _>`
+              found struct `A<'b, u32, _, _>`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/types-mismatch-const-args.rs:18:41
+   |
+LL |     let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+   |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `A<'a, u16, 4_u32, _>`
+              found struct `A<'b, u32, 2_u32, _>`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr
index ec9221d2486..8b60238cb0c 100644
--- a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr
+++ b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr
@@ -20,6 +20,17 @@ LL |     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data
    = note: expected struct `A<'a, u16, _, _>`
               found struct `A<'b, u32, _, _>`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/types-mismatch-const-args.rs:18:41
+   |
+LL |     let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+   |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `A<'a, u16, 4_u32, _>`
+              found struct `A<'b, u32, 2_u32, _>`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.rs b/src/test/ui/const-generics/types-mismatch-const-args.rs
index c2092c4268e..43ef28b268f 100644
--- a/src/test/ui/const-generics/types-mismatch-const-args.rs
+++ b/src/test/ui/const-generics/types-mismatch-const-args.rs
@@ -15,6 +15,8 @@ fn a<'a, 'b>() {
     //~^ ERROR mismatched types
     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
     //~^ ERROR mismatched types
+    let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+    //~^ ERROR mismatched types
 }
 
 pub fn main() {}
diff --git a/src/test/ui/consts/const-block-const-bound.rs b/src/test/ui/consts/const-block-const-bound.rs
index 3bfc759a9ae..3d7e171f18c 100644
--- a/src/test/ui/consts/const-block-const-bound.rs
+++ b/src/test/ui/consts/const-block-const-bound.rs
@@ -1,5 +1,5 @@
 #![allow(unused)]
-#![feature(const_fn_trait_bound, const_trait_impl, inline_const)]
+#![feature(const_fn_trait_bound, const_trait_impl, inline_const, negative_impls)]
 
 const fn f<T: ~const Drop>(x: T) {}
 
@@ -9,9 +9,15 @@ impl Drop for UnconstDrop {
     fn drop(&mut self) {}
 }
 
+struct NonDrop;
+
+impl !Drop for NonDrop {}
+
 fn main() {
     const {
         f(UnconstDrop);
         //~^ ERROR the trait bound `UnconstDrop: Drop` is not satisfied
+        f(NonDrop);
+        //~^ ERROR the trait bound `NonDrop: Drop` is not satisfied
     }
 }
diff --git a/src/test/ui/consts/const-block-const-bound.stderr b/src/test/ui/consts/const-block-const-bound.stderr
index 0e6e426e7c2..5f912c66bb9 100644
--- a/src/test/ui/consts/const-block-const-bound.stderr
+++ b/src/test/ui/consts/const-block-const-bound.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `UnconstDrop: Drop` is not satisfied
-  --> $DIR/const-block-const-bound.rs:14:11
+  --> $DIR/const-block-const-bound.rs:18:11
    |
 LL |         f(UnconstDrop);
    |         - ^^^^^^^^^^^ the trait `Drop` is not implemented for `UnconstDrop`
@@ -16,6 +16,20 @@ help: consider introducing a `where` bound, but there might be an alternative be
 LL | fn main() where UnconstDrop: Drop {
    |           +++++++++++++++++++++++
 
-error: aborting due to previous error
+error[E0277]: the trait bound `NonDrop: Drop` is not satisfied
+  --> $DIR/const-block-const-bound.rs:20:11
+   |
+LL |         f(NonDrop);
+   |         - ^^^^^^^ the trait `Drop` is not implemented for `NonDrop`
+   |         |
+   |         required by a bound introduced by this call
+   |
+note: required by a bound in `f`
+  --> $DIR/const-block-const-bound.rs:4:15
+   |
+LL | const fn f<T: ~const Drop>(x: T) {}
+   |               ^^^^^^^^^^^ required by this bound in `f`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr
index 72607629d3c..2a44e56a330 100644
--- a/src/test/ui/derive-uninhabited-enum-38885.stderr
+++ b/src/test/ui/derive-uninhabited-enum-38885.stderr
@@ -5,6 +5,12 @@ LL |     Void(Void),
    |     ^^^^^^^^^^
    |
    = note: `-W dead-code` implied by `-W unused`
+note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
+  --> $DIR/derive-uninhabited-enum-38885.rs:10:10
+   |
+LL | #[derive(Debug)]
+   |          ^^^^^
+   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/derives/clone-debug-dead-code.stderr b/src/test/ui/derives/clone-debug-dead-code.stderr
index 226007f3647..67bb574315a 100644
--- a/src/test/ui/derives/clone-debug-dead-code.stderr
+++ b/src/test/ui/derives/clone-debug-dead-code.stderr
@@ -15,18 +15,39 @@ error: field is never read: `f`
    |
 LL | struct B { f: () }
    |            ^^^^^
+   |
+note: `B` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
+  --> $DIR/clone-debug-dead-code.rs:9:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:14:12
    |
 LL | struct C { f: () }
    |            ^^^^^
+   |
+note: `C` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
+  --> $DIR/clone-debug-dead-code.rs:13:10
+   |
+LL | #[derive(Debug)]
+   |          ^^^^^
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:18:12
    |
 LL | struct D { f: () }
    |            ^^^^^
+   |
+note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
+  --> $DIR/clone-debug-dead-code.rs:17:10
+   |
+LL | #[derive(Debug,Clone)]
+   |          ^^^^^ ^^^^^
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:21:12
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs
index 609a5b0de6b..f787c416c2d 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs
@@ -16,7 +16,7 @@ type D = (u8, u8)::AssocTy;
 
 type E = _::AssocTy;
 //~^ ERROR missing angle brackets in associated item path
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for type aliases
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for type aliases
 
 type F = &'static (u8)::AssocTy;
 //~^ ERROR missing angle brackets in associated item path
@@ -49,37 +49,37 @@ type I = ty!()::AssocTy;
 
 trait K<A, B> {}
 fn foo<X: K<_, _>>(x: X) {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn bar<F>(_: F) where F: Fn() -> _ {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn baz<F: Fn() -> _>(_: F) {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 struct L<F>(F) where F: Fn() -> _;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
 struct M<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
     a: F,
 }
 enum N<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for enums
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for enums
     Foo(F),
 }
 
 union O<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for unions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for unions
     foo: F,
 }
 
 trait P<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for traits
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for traits
 }
 
 trait Q {
     fn foo<F>(_: F) where F: Fn() -> _ {}
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 fn main() {}
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
index 11514a28b2c..2326af934d0 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
@@ -81,7 +81,7 @@ error[E0223]: ambiguous associated type
 LL | type D = (u8, u8)::AssocTy;
    |          ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for type aliases
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
   --> $DIR/bad-assoc-ty.rs:17:10
    |
 LL | type E = _::AssocTy;
@@ -136,7 +136,7 @@ error[E0223]: ambiguous associated type
 LL | type I = ty!()::AssocTy;
    |          ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:51:13
    |
 LL | fn foo<X: K<_, _>>(x: X) {}
@@ -149,7 +149,7 @@ help: use type parameters instead
 LL | fn foo<X: K<T, T>, T>(x: X) {}
    |             ~  ~ +++
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:54:34
    |
 LL | fn bar<F>(_: F) where F: Fn() -> _ {}
@@ -160,7 +160,7 @@ help: use type parameters instead
 LL | fn bar<F, T>(_: F) where F: Fn() -> T {}
    |         +++                         ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:57:19
    |
 LL | fn baz<F: Fn() -> _>(_: F) {}
@@ -171,7 +171,7 @@ help: use type parameters instead
 LL | fn baz<F: Fn() -> T, T>(_: F) {}
    |                   ~+++
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/bad-assoc-ty.rs:60:33
    |
 LL | struct L<F>(F) where F: Fn() -> _;
@@ -182,7 +182,7 @@ help: use type parameters instead
 LL | struct L<F, T>(F) where F: Fn() -> T;
    |           +++                      ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/bad-assoc-ty.rs:62:30
    |
 LL | struct M<F> where F: Fn() -> _ {
@@ -193,7 +193,7 @@ help: use type parameters instead
 LL | struct M<F, T> where F: Fn() -> T {
    |           +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for enums
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for enums
   --> $DIR/bad-assoc-ty.rs:66:28
    |
 LL | enum N<F> where F: Fn() -> _ {
@@ -204,7 +204,7 @@ help: use type parameters instead
 LL | enum N<F, T> where F: Fn() -> T {
    |         +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for unions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for unions
   --> $DIR/bad-assoc-ty.rs:71:29
    |
 LL | union O<F> where F: Fn() -> _ {
@@ -215,7 +215,7 @@ help: use type parameters instead
 LL | union O<F, T> where F: Fn() -> T {
    |          +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for traits
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for traits
   --> $DIR/bad-assoc-ty.rs:76:29
    |
 LL | trait P<F> where F: Fn() -> _ {
@@ -226,7 +226,7 @@ help: use type parameters instead
 LL | trait P<F, T> where F: Fn() -> T {
    |          +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:81:38
    |
 LL |     fn foo<F>(_: F) where F: Fn() -> _ {}
diff --git a/src/test/ui/error-codes/E0121.stderr b/src/test/ui/error-codes/E0121.stderr
index cc0c2df72ea..023d7e011bf 100644
--- a/src/test/ui/error-codes/E0121.stderr
+++ b/src/test/ui/error-codes/E0121.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/E0121.rs:1:13
    |
 LL | fn foo() -> _ { 5 }
@@ -7,7 +7,7 @@ LL | fn foo() -> _ { 5 }
    |             not allowed in type signatures
    |             help: replace with the correct return type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/E0121.rs:3:13
    |
 LL | static BAR: _ = "test";
diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.rs b/src/test/ui/expr/if/attrs/let-chains-attr.rs
index 5237a9ff396..2cd8731141a 100644
--- a/src/test/ui/expr/if/attrs/let-chains-attr.rs
+++ b/src/test/ui/expr/if/attrs/let-chains-attr.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
+#![feature(let_chains)]
 
 #[cfg(FALSE)]
 fn foo() {
diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.stderr b/src/test/ui/expr/if/attrs/let-chains-attr.stderr
deleted file mode 100644
index 8b987471534..00000000000
--- a/src/test/ui/expr/if/attrs/let-chains-attr.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/let-chains-attr.rs:3:12
-   |
-LL | #![feature(let_chains)]
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs b/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs
new file mode 100644
index 00000000000..b51ead2a188
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs
@@ -0,0 +1,16 @@
+pub trait TraitWAssocConst {
+  const A: usize;
+}
+pub struct Demo {}
+
+impl TraitWAssocConst for Demo {
+  const A: usize = 32;
+}
+
+fn foo<A: TraitWAssocConst<A=32>>() {}
+//~^ ERROR associated const equality
+//~| ERROR associated const equality
+
+fn main() {
+  foo::<Demo>();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr b/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr
new file mode 100644
index 00000000000..f4db49c4af8
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr
@@ -0,0 +1,18 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/feature-gate-associated_const_equality.rs:10:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {}
+   |                            ^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error: associated const equality is incomplete
+  --> $DIR/feature-gate-associated_const_equality.rs:10:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {}
+   |                            ^^^^ cannot yet relate associated const
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs
deleted file mode 100644
index 33f9c539313..00000000000
--- a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// gate-test-raw_dylib
-// only-windows-gnu
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: kind="raw-dylib" is unstable
-//~| WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-extern "C" {}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr
deleted file mode 100644
index 14dfadf4126..00000000000
--- a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-  --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0658]: kind="raw-dylib" is unstable
-  --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib.rs
index 49de24ea9ab..995d9ced480 100644
--- a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs
+++ b/src/test/ui/feature-gates/feature-gate-raw-dylib.rs
@@ -1,5 +1,4 @@
-// gate-test-raw_dylib
-// only-windows-msvc
+// only-windows
 #[link(name = "foo", kind = "raw-dylib")]
 //~^ ERROR: kind="raw-dylib" is unstable
 extern "C" {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr
index 11988080812..bb64af38b2c 100644
--- a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr
+++ b/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr
@@ -1,5 +1,5 @@
 error[E0658]: kind="raw-dylib" is unstable
-  --> $DIR/feature-gate-raw-dylib-windows-msvc.rs:3:1
+  --> $DIR/feature-gate-raw-dylib.rs:2:1
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index 1ddf8508cc8..ed382406efa 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -1,6 +1,7 @@
 //~ NOTE not a function
-//~^ NOTE not a foreign function or static
-//~^^ NOTE not a function or static
+//~| NOTE not a foreign function or static
+//~| NOTE not a function or static
+//~| NOTE not an `extern` block
 // This test enumerates as many compiler-builtin ungated attributes as
 // possible (that is, all the mutually compatible ones), and checks
 // that we get "expected" (*) warnings for each in the various weird
@@ -59,9 +60,9 @@
 #![proc_macro_derive()] //~ WARN `#[proc_macro_derive]` only has an effect
 #![doc = "2400"]
 #![cold] //~ WARN attribute should be applied to a function
-//~^ WARN
-// see issue-43106-gating-of-builtin-attrs-error.rs
-#![link()]
+//~^ WARN this was previously accepted
+#![link()] //~ WARN attribute should be applied to an `extern` block
+//~^ WARN this was previously accepted
 #![link_name = "1900"]
 //~^ WARN attribute should be applied to a foreign function
 //~^^ WARN this was previously accepted by the compiler
@@ -547,22 +548,38 @@ mod link_section {
 }
 
 
-// Note that this is a `check-pass` test, so it
-// will never invoke the linker. These are here nonetheless to point
-// out that we allow them at non-crate-level (though I do not know
-// whether they have the same effect here as at crate-level).
+// Note that this is a `check-pass` test, so it will never invoke the linker.
 
 #[link()]
+//~^ WARN attribute should be applied to an `extern` block
+//~| WARN this was previously accepted
 mod link {
+    //~^ NOTE not an `extern` block
+
     mod inner { #![link()] }
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] fn f() { }
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] struct S;
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] type T = S;
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] impl S { }
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 }
 
 struct StructForDeprecated;
@@ -594,16 +611,22 @@ mod must_use {
 }
 
 #[windows_subsystem = "windows"]
+//~^ WARN crate-level attribute should be an inner attribute
 mod windows_subsystem {
     mod inner { #![windows_subsystem="windows"] }
+    //~^ WARN crate-level attribute should be in the root module
 
     #[windows_subsystem = "windows"] fn f() { }
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[windows_subsystem = "windows"] struct S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[windows_subsystem = "windows"] type T = S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[windows_subsystem = "windows"] impl S { }
+    //~^ WARN crate-level attribute should be an inner attribute
 }
 
 // BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES
@@ -686,16 +709,22 @@ mod no_main_1 {
 }
 
 #[no_builtins]
+//~^ WARN crate-level attribute should be an inner attribute
 mod no_builtins {
     mod inner { #![no_builtins] }
+    //~^ WARN crate-level attribute should be in the root module
 
     #[no_builtins] fn f() { }
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[no_builtins] struct S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[no_builtins] type T = S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[no_builtins] impl S { }
+    //~^ WARN crate-level attribute should be an inner attribute
 }
 
 #[recursion_limit="0200"]
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index b98374bfa80..bd3e33320c3 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -1,179 +1,179 @@
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:9
    |
 LL | #![warn(x5400)]
    |         ^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:28
    |
 LL | #![warn(unused_attributes, unknown_lints)]
    |                            ^^^^^^^^^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:10
    |
 LL | #![allow(x5300)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:11
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:11
    |
 LL | #![forbid(x5200)]
    |           ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:9
    |
 LL | #![deny(x5100)]
    |         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:104:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:8
    |
 LL | #[warn(x5400)]
    |        ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:107:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:25
    |
 LL |     mod inner { #![warn(x5400)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12
    |
 LL |     #[warn(x5400)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:12
    |
 LL |     #[warn(x5400)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12
    |
 LL |     #[warn(x5400)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12
    |
 LL |     #[warn(x5400)] impl S { }
    |            ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:9
    |
 LL | #[allow(x5300)]
    |         ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:26
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:26
    |
 LL |     mod inner { #![allow(x5300)] }
    |                          ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13
    |
 LL |     #[allow(x5300)] fn f() { }
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:13
    |
 LL |     #[allow(x5300)] struct S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13
    |
 LL |     #[allow(x5300)] type T = S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13
    |
 LL |     #[allow(x5300)] impl S { }
    |             ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:10
    |
 LL | #[forbid(x5200)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:27
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:27
    |
 LL |     mod inner { #![forbid(x5200)] }
    |                           ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14
    |
 LL |     #[forbid(x5200)] fn f() { }
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:14
    |
 LL |     #[forbid(x5200)] struct S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14
    |
 LL |     #[forbid(x5200)] type T = S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14
    |
 LL |     #[forbid(x5200)] impl S { }
    |              ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:8
    |
 LL | #[deny(x5100)]
    |        ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:25
    |
 LL |     mod inner { #![deny(x5100)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12
    |
 LL |     #[deny(x5100)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:12
    |
 LL |     #[deny(x5100)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12
    |
 LL |     #[deny(x5100)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12
    |
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:400:17
    |
 LL |     mod inner { #![macro_escape] }
    |                 ^^^^^^^^^^^^^^^^
@@ -181,13 +181,13 @@ LL |     mod inner { #![macro_escape] }
    = help: try an outer attribute: `#[macro_use]`
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:1
    |
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
 
 warning: use of deprecated attribute `crate_id`: no longer used.
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:83:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:84:1
    |
 LL | #![crate_id = "10"]
    | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
@@ -195,31 +195,31 @@ LL | #![crate_id = "10"]
    = note: `#[warn(deprecated)]` on by default
 
 warning: use of deprecated attribute `no_start`: no longer used.
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:93:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:1
    |
 LL | #![no_start]
    | ^^^^^^^^^^^^ help: remove this attribute
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:1
    |
 LL | #[macro_export]
    | ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:9
    |
 LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:284:1
    |
 LL |   #[no_mangle]
    |   ^^^^^^^^^^^^
@@ -236,31 +236,31 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:1
    |
 LL | #[reexport_test_harness_main = "2900"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:416:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:1
    |
 LL |   #[cold]
    |   ^^^^^^^
@@ -277,7 +277,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:1
    |
 LL |   #[link_name = "1900"]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -294,7 +294,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:521:1
    |
 LL |   #[link_section = "1800"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -310,70 +310,107 @@ LL | | }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:553:1
+   |
+LL |   #[link()]
+   |   ^^^^^^^^^
+...
+LL | / mod link {
+LL | |
+LL | |
+LL | |     mod inner { #![link()] }
+...  |
+LL | |
+LL | | }
+   | |_- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:613:1
+   |
+LL | #[windows_subsystem = "windows"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:653:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:1
+   |
+LL | #[no_builtins]
+   | ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
    |
 LL | #![should_panic]
    | ^^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1
    |
 LL | #![ignore]
    | ^^^^^^^^^^
 
 warning: `#[proc_macro_derive]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
    |
 LL | #![proc_macro_derive()]
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
    |
 LL | #![cold]
    | ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
+   |
+LL | #![link()]
+   | ^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1
    |
 LL | #![link_name = "1900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -381,7 +418,7 @@ LL | #![link_name = "1900"]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
    |
 LL | #![link_section = "1800"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -389,109 +426,109 @@ LL | #![link_section = "1800"]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5
    |
 LL |     #[macro_use] fn f() { }
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:187:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5
    |
 LL |     #[macro_use] struct S;
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5
    |
 LL |     #[macro_use] type T = S;
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:5
    |
 LL |     #[macro_use] impl S { }
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:200:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:17
    |
 LL |     mod inner { #![macro_export] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5
    |
 LL |     #[macro_export] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:206:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5
    |
 LL |     #[macro_export] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5
    |
 LL |     #[macro_export] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5
    |
 LL |     #[macro_export] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:253:5
    |
 LL |     #[path = "3800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5
    |
 LL |     #[path = "3800"]  struct S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:259:5
    |
 LL |     #[path = "3800"] type T = S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:5
    |
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:277:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:5
    |
 LL |     #[automatically_derived] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:288:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:17
    |
 LL |     mod inner { #![no_mangle] }
    |     ------------^^^^^^^^^^^^^-- not a free function, impl method or static
@@ -499,7 +536,7 @@ LL |     mod inner { #![no_mangle] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:295:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:296:5
    |
 LL |     #[no_mangle] struct S;
    |     ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -507,7 +544,7 @@ LL |     #[no_mangle] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:300:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:301:5
    |
 LL |     #[no_mangle] type T = S;
    |     ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -515,7 +552,7 @@ LL |     #[no_mangle] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:305:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:306:5
    |
 LL |     #[no_mangle] impl S { }
    |     ^^^^^^^^^^^^ ---------- not a free function, impl method or static
@@ -523,7 +560,7 @@ LL |     #[no_mangle] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:311:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:312:9
    |
 LL |         #[no_mangle] fn foo();
    |         ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -531,7 +568,7 @@ LL |         #[no_mangle] fn foo();
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:316:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:317:9
    |
 LL |         #[no_mangle] fn bar() {}
    |         ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -539,163 +576,163 @@ LL |         #[no_mangle] fn bar() {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:327:17
    |
 LL |     mod inner { #![should_panic] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5
    |
 LL |     #[should_panic] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5
    |
 LL |     #[should_panic] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:337:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5
    |
 LL |     #[should_panic] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:17
    |
 LL |     mod inner { #![ignore] }
    |                 ^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:349:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5
    |
 LL |     #[ignore] struct S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:352:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5
    |
 LL |     #[ignore] type T = S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:356:5
    |
 LL |     #[ignore] impl S { }
    |     ^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:363:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5
    |
 LL |     #[no_implicit_prelude] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:366:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
    |
 LL |     #[no_implicit_prelude] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:369:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
    |
 LL |     #[no_implicit_prelude] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:372:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5
    |
 LL |     #[no_implicit_prelude] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:17
    |
 LL |     mod inner { #![reexport_test_harness_main="2900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5
    |
 LL |     #[reexport_test_harness_main = "2900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5
    |
 LL |     #[reexport_test_harness_main = "2900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5
    |
 LL |     #[reexport_test_harness_main = "2900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5
    |
 LL |     #[reexport_test_harness_main = "2900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:403:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5
    |
 LL |     #[macro_escape] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5
    |
 LL |     #[macro_escape] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:409:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5
    |
 LL |     #[macro_escape] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:413:5
    |
 LL |     #[macro_escape] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:419:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:422:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:17
    |
 LL |     mod inner { #![cold] }
    |     ------------^^^^^^^^-- not a function
@@ -703,7 +740,7 @@ LL |     mod inner { #![cold] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5
    |
 LL |     #[cold] struct S;
    |     ^^^^^^^ --------- not a function
@@ -711,7 +748,7 @@ LL |     #[cold] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5
    |
 LL |     #[cold] type T = S;
    |     ^^^^^^^ ----------- not a function
@@ -719,7 +756,7 @@ LL |     #[cold] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5
    |
 LL |     #[cold] impl S { }
    |     ^^^^^^^ ---------- not a function
@@ -727,7 +764,7 @@ LL |     #[cold] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -737,13 +774,13 @@ LL |     extern "C" { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 help: try `#[link(name = "1900")]` instead
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:17
    |
 LL |     mod inner { #![link_name="1900"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static
@@ -751,7 +788,7 @@ LL |     mod inner { #![link_name="1900"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:5
    |
 LL |     #[link_name = "1900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -759,7 +796,7 @@ LL |     #[link_name = "1900"] fn f() { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:504:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5
    |
 LL |     #[link_name = "1900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static
@@ -767,7 +804,7 @@ LL |     #[link_name = "1900"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:509:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:510:5
    |
 LL |     #[link_name = "1900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static
@@ -775,7 +812,7 @@ LL |     #[link_name = "1900"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:514:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5
    |
 LL |     #[link_name = "1900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -783,7 +820,7 @@ LL |     #[link_name = "1900"] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:527:17
    |
 LL |     mod inner { #![link_section="1800"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static
@@ -791,7 +828,7 @@ LL |     mod inner { #![link_section="1800"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:534:5
    |
 LL |     #[link_section = "1800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static
@@ -799,7 +836,7 @@ LL |     #[link_section = "1800"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:538:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:539:5
    |
 LL |     #[link_section = "1800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static
@@ -807,200 +844,300 @@ LL |     #[link_section = "1800"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:543:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5
    |
 LL |     #[link_section = "1800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:17
+   |
+LL |     mod inner { #![link()] }
+   |     ------------^^^^^^^^^^-- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:564:5
+   |
+LL |     #[link()] fn f() { }
+   |     ^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:5
+   |
+LL |     #[link()] struct S;
+   |     ^^^^^^^^^ --------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:574:5
+   |
+LL |     #[link()] type T = S;
+   |     ^^^^^^^^^ ----------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:579:5
+   |
+LL |     #[link()] impl S { }
+   |     ^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:616:17
+   |
+LL |     mod inner { #![windows_subsystem="windows"] }
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:5
+   |
+LL |     #[windows_subsystem = "windows"] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:5
+   |
+LL |     #[windows_subsystem = "windows"] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:5
+   |
+LL |     #[windows_subsystem = "windows"] type T = S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:628:5
+   |
+LL |     #[windows_subsystem = "windows"] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be in the root module
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:637:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:636:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:662:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:678:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:678:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17
+   |
+LL |     mod inner { #![no_builtins] }
+   |                 ^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5
+   |
+LL |     #[no_builtins] fn f() { }
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5
+   |
+LL |     #[no_builtins] struct S;
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5
+   |
+LL |     #[no_builtins] type T = S;
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
+   |
+LL |     #[no_builtins] impl S { }
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be in the root module
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:89:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:12
    |
 LL | #![feature(rust1)]
    |            ^^^^^
    |
    = note: `#[warn(stable_features)]` on by default
 
-warning: 148 warnings emitted
+warning: 167 warnings emitted
 
diff --git a/src/test/ui/fn/issue-80179.rs b/src/test/ui/fn/issue-80179.rs
index 550974bf778..fcef6f1b60e 100644
--- a/src/test/ui/fn/issue-80179.rs
+++ b/src/test/ui/fn/issue-80179.rs
@@ -8,7 +8,7 @@ fn returns_i32() -> i32 {
 }
 
 fn returns_fn_ptr() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types [E0121]
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
 //~| NOTE not allowed in type signatures
 //~| HELP replace with the correct return type
 //~| SUGGESTION fn() -> i32
@@ -16,7 +16,7 @@ fn returns_fn_ptr() -> _ {
 }
 
 fn returns_closure() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types [E0121]
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
 //~| NOTE not allowed in type signatures
 //~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
 //~| NOTE for more information on `Fn` traits and closure types, see
diff --git a/src/test/ui/fn/issue-80179.stderr b/src/test/ui/fn/issue-80179.stderr
index 96d0f02b01a..2ca4ae982d9 100644
--- a/src/test/ui/fn/issue-80179.stderr
+++ b/src/test/ui/fn/issue-80179.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80179.rs:10:24
    |
 LL | fn returns_fn_ptr() -> _ {
@@ -7,7 +7,7 @@ LL | fn returns_fn_ptr() -> _ {
    |                        not allowed in type signatures
    |                        help: replace with the correct return type: `fn() -> i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80179.rs:18:25
    |
 LL | fn returns_closure() -> _ {
diff --git a/src/test/ui/generator/drop-control-flow.rs b/src/test/ui/generator/drop-control-flow.rs
new file mode 100644
index 00000000000..6319a29f5b7
--- /dev/null
+++ b/src/test/ui/generator/drop-control-flow.rs
@@ -0,0 +1,121 @@
+// build-pass
+
+// A test to ensure generators capture values that were conditionally dropped,
+// and also that values that are dropped along all paths to a yield do not get
+// included in the generator type.
+
+#![feature(generators, negative_impls)]
+#![allow(unused_assignments, dead_code)]
+
+struct Ptr;
+impl<'a> Drop for Ptr {
+    fn drop(&mut self) {}
+}
+
+struct NonSend;
+impl !Send for NonSend {}
+
+fn assert_send<T: Send>(_: T) {}
+
+// This test case is reduced from src/test/ui/drop/dynamic-drop-async.rs
+fn one_armed_if(arg: bool) {
+    let _ = || {
+        let arr = [Ptr];
+        if arg {
+            drop(arr);
+        }
+        yield;
+    };
+}
+
+fn two_armed_if(arg: bool) {
+    assert_send(|| {
+        let arr = [Ptr];
+        if arg {
+            drop(arr);
+        } else {
+            drop(arr);
+        }
+        yield;
+    })
+}
+
+fn if_let(arg: Option<i32>) {
+    let _ = || {
+        let arr = [Ptr];
+        if let Some(_) = arg {
+            drop(arr);
+        }
+        yield;
+    };
+}
+
+fn init_in_if(arg: bool) {
+    assert_send(|| {
+        let mut x = NonSend;
+        drop(x);
+        if arg {
+            x = NonSend;
+        } else {
+            yield;
+        }
+    })
+}
+
+fn init_in_match_arm(arg: Option<i32>) {
+    assert_send(|| {
+        let mut x = NonSend;
+        drop(x);
+        match arg {
+            Some(_) => x = NonSend,
+            None => yield,
+        }
+    })
+}
+
+fn reinit() {
+    let _ = || {
+        let mut arr = [Ptr];
+        drop(arr);
+        arr = [Ptr];
+        yield;
+    };
+}
+
+fn loop_uninit() {
+    let _ = || {
+        let mut arr = [Ptr];
+        let mut count = 0;
+        drop(arr);
+        while count < 3 {
+            yield;
+            arr = [Ptr];
+            count += 1;
+        }
+    };
+}
+
+fn nested_loop() {
+    let _ = || {
+        let mut arr = [Ptr];
+        let mut count = 0;
+        drop(arr);
+        while count < 3 {
+            for _ in 0..3 {
+                yield;
+            }
+            arr = [Ptr];
+            count += 1;
+        }
+    };
+}
+
+fn main() {
+    one_armed_if(true);
+    if_let(Some(41));
+    init_in_if(true);
+    init_in_match_arm(Some(41));
+    reinit();
+    loop_uninit();
+    nested_loop();
+}
diff --git a/src/test/ui/generator/drop-yield-twice.rs b/src/test/ui/generator/drop-yield-twice.rs
new file mode 100644
index 00000000000..f484cbb8d67
--- /dev/null
+++ b/src/test/ui/generator/drop-yield-twice.rs
@@ -0,0 +1,15 @@
+#![feature(negative_impls, generators)]
+
+struct Foo(i32);
+impl !Send for Foo {}
+
+fn main() {
+    assert_send(|| { //~ ERROR generator cannot be sent between threads safely
+        let guard = Foo(42);
+        yield;
+        drop(guard);
+        yield;
+    })
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/drop-yield-twice.stderr b/src/test/ui/generator/drop-yield-twice.stderr
new file mode 100644
index 00000000000..f821f2f4005
--- /dev/null
+++ b/src/test/ui/generator/drop-yield-twice.stderr
@@ -0,0 +1,25 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-yield-twice.rs:7:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/drop-yield-twice.rs:7:17: 12:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-yield-twice.rs:9:9
+   |
+LL |         let guard = Foo(42);
+   |             ----- has type `Foo` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+...
+LL |     })
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/drop-yield-twice.rs:15:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/issue-57478.rs b/src/test/ui/generator/issue-57478.rs
new file mode 100644
index 00000000000..39710febdb9
--- /dev/null
+++ b/src/test/ui/generator/issue-57478.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(negative_impls, generators)]
+
+struct Foo;
+impl !Send for Foo {}
+
+fn main() {
+    assert_send(|| {
+        let guard = Foo;
+        drop(guard);
+        yield;
+    })
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/partial-drop.rs b/src/test/ui/generator/partial-drop.rs
new file mode 100644
index 00000000000..36f6e78cb3b
--- /dev/null
+++ b/src/test/ui/generator/partial-drop.rs
@@ -0,0 +1,40 @@
+#![feature(negative_impls, generators)]
+
+struct Foo;
+impl !Send for Foo {}
+
+struct Bar {
+    foo: Foo,
+    x: i32,
+}
+
+fn main() {
+    assert_send(|| {
+        //~^ ERROR generator cannot be sent between threads safely
+        // FIXME: it would be nice to make this work.
+        let guard = Bar { foo: Foo, x: 42 };
+        drop(guard.foo);
+        yield;
+    });
+
+    assert_send(|| {
+        //~^ ERROR generator cannot be sent between threads safely
+        // FIXME: it would be nice to make this work.
+        let guard = Bar { foo: Foo, x: 42 };
+        drop(guard);
+        guard.foo = Foo;
+        guard.x = 23;
+        yield;
+    });
+
+    assert_send(|| {
+        //~^ ERROR generator cannot be sent between threads safely
+        // FIXME: it would be nice to make this work.
+        let guard = Bar { foo: Foo, x: 42 };
+        let Bar { foo, x } = guard;
+        drop(foo);
+        yield;
+    });
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/partial-drop.stderr b/src/test/ui/generator/partial-drop.stderr
new file mode 100644
index 00000000000..9a1b0734d8c
--- /dev/null
+++ b/src/test/ui/generator/partial-drop.stderr
@@ -0,0 +1,71 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:12:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:12:17: 18:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:17:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+LL |         drop(guard.foo);
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:20:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:20:17: 28:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:27:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+...
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:30:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:30:17: 37:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:36:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+...
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/generator/reinit-in-match-guard.rs b/src/test/ui/generator/reinit-in-match-guard.rs
new file mode 100644
index 00000000000..260b341a525
--- /dev/null
+++ b/src/test/ui/generator/reinit-in-match-guard.rs
@@ -0,0 +1,25 @@
+// build-pass
+
+#![feature(generators)]
+
+#![allow(unused_assignments, dead_code)]
+
+fn main() {
+    let _ = || {
+        let mut x = vec![22_usize];
+        std::mem::drop(x);
+        match y() {
+            true if {
+                x = vec![];
+                false
+            } => {}
+            _ => {
+                yield;
+            }
+        }
+    };
+}
+
+fn y() -> bool {
+    true
+}
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.stderr b/src/test/ui/hygiene/rustc-macro-transparency.stderr
index e4c1c8ad293..17d05dd0963 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.stderr
+++ b/src/test/ui/hygiene/rustc-macro-transparency.stderr
@@ -11,16 +11,10 @@ LL |     struct SemiTransparent;
    |     ----------------------- similarly named unit struct `SemiTransparent` defined here
 ...
 LL |     semitransparent;
-   |     ^^^^^^^^^^^^^^^ not a value
-   |
-help: use `!` to invoke the macro
-   |
-LL |     semitransparent!;
-   |                    +
-help: a unit struct with a similar name exists
-   |
-LL |     SemiTransparent;
-   |     ~~~~~~~~~~~~~~~
+   |     ^^^^^^^^^^^^^^^
+   |     |
+   |     not a value
+   |     help: a unit struct with a similar name exists: `SemiTransparent`
 
 error[E0423]: expected value, found macro `opaque`
   --> $DIR/rustc-macro-transparency.rs:30:5
@@ -29,16 +23,10 @@ LL |     struct Opaque;
    |     -------------- similarly named unit struct `Opaque` defined here
 ...
 LL |     opaque;
-   |     ^^^^^^ not a value
-   |
-help: use `!` to invoke the macro
-   |
-LL |     opaque!;
-   |           +
-help: a unit struct with a similar name exists
-   |
-LL |     Opaque;
-   |     ~~~~~~
+   |     ^^^^^^
+   |     |
+   |     not a value
+   |     help: a unit struct with a similar name exists (notice the capitalization): `Opaque`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs b/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs
index 6880e1a4629..45a30857413 100644
--- a/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs
+++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs
@@ -4,7 +4,7 @@ macro_rules! suite {
             const A = "A".$fn();
             //~^ ERROR the name `A` is defined multiple times
             //~| ERROR missing type for `const` item
-            //~| ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+            //~| ERROR the placeholder `_` is not allowed within types on item signatures for constants
         )*
     }
 }
diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
index 34c2073db04..e5ab65169ce 100644
--- a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
+++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
@@ -30,7 +30,7 @@ LL | | }
    |
    = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
    |
 LL |               const A = "A".$fn();
diff --git a/src/test/ui/lint/dead-code/unused-variant.stderr b/src/test/ui/lint/dead-code/unused-variant.stderr
index a547f5af4b0..3b5683a7748 100644
--- a/src/test/ui/lint/dead-code/unused-variant.stderr
+++ b/src/test/ui/lint/dead-code/unused-variant.stderr
@@ -9,6 +9,12 @@ note: the lint level is defined here
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
+note: `Enum` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
+  --> $DIR/unused-variant.rs:3:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/must_not_suspend/dedup.rs b/src/test/ui/lint/must_not_suspend/dedup.rs
index 040fff5a5a5..81a08579bb7 100644
--- a/src/test/ui/lint/must_not_suspend/dedup.rs
+++ b/src/test/ui/lint/must_not_suspend/dedup.rs
@@ -13,7 +13,7 @@ async fn wheeee<T>(t: T) {
 }
 
 async fn yes() {
-    wheeee(No {}).await; //~ ERROR `No` held across
+    wheeee(&No {}).await; //~ ERROR `No` held across
 }
 
 fn main() {
diff --git a/src/test/ui/lint/must_not_suspend/dedup.stderr b/src/test/ui/lint/must_not_suspend/dedup.stderr
index bc1b611299a..13fa3ae3008 100644
--- a/src/test/ui/lint/must_not_suspend/dedup.stderr
+++ b/src/test/ui/lint/must_not_suspend/dedup.stderr
@@ -1,8 +1,8 @@
 error: `No` held across a suspend point, but should not be
-  --> $DIR/dedup.rs:16:12
+  --> $DIR/dedup.rs:16:13
    |
-LL |     wheeee(No {}).await;
-   |            ^^^^^ ------ the value is held across this suspend point
+LL |     wheeee(&No {}).await;
+   |             ^^^^^ ------ the value is held across this suspend point
    |
 note: the lint level is defined here
   --> $DIR/dedup.rs:3:9
@@ -10,10 +10,10 @@ note: the lint level is defined here
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/dedup.rs:16:12
+  --> $DIR/dedup.rs:16:13
    |
-LL |     wheeee(No {}).await;
-   |            ^^^^^
+LL |     wheeee(&No {}).await;
+   |             ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/macro-interpolation.rs b/src/test/ui/macros/macro-interpolation.rs
index abe1f2aaf15..35003a79ad7 100644
--- a/src/test/ui/macros/macro-interpolation.rs
+++ b/src/test/ui/macros/macro-interpolation.rs
@@ -14,8 +14,20 @@ macro_rules! overly_complicated {
 
 }
 
+macro_rules! qpath {
+    (path, <$type:ty as $trait:path>::$name:ident) => {
+        <$type as $trait>::$name
+    };
+
+    (ty, <$type:ty as $trait:ty>::$name:ident) => {
+        <$type as $trait>::$name
+    };
+}
+
 pub fn main() {
+    let _: qpath!(path, <str as ToOwned>::Owned);
+    let _: qpath!(ty, <str as ToOwned>::Owned);
+
     assert!(overly_complicated!(f, x, Option<usize>, { return Some(x); },
                                Some(8), Some(y), y) == 8)
-
 }
diff --git a/src/test/ui/mir/mir_let_chains_drop_order.rs b/src/test/ui/mir/mir_let_chains_drop_order.rs
new file mode 100644
index 00000000000..01f943c87dd
--- /dev/null
+++ b/src/test/ui/mir/mir_let_chains_drop_order.rs
@@ -0,0 +1,93 @@
+// run-pass
+// needs-unwind
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// See `mir_drop_order.rs` for more information
+
+#![feature(let_chains)]
+
+use std::cell::RefCell;
+use std::panic;
+
+pub struct DropLogger<'a, T> {
+    extra: T,
+    id: usize,
+    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>
+}
+
+impl<'a, T> Drop for DropLogger<'a, T> {
+    fn drop(&mut self) {
+        self.log.0.borrow_mut().push(self.id);
+    }
+}
+
+struct InjectedFailure;
+
+#[allow(unreachable_code)]
+fn main() {
+    let log = panic::AssertUnwindSafe(RefCell::new(vec![]));
+    let d = |id, extra| DropLogger { extra, id: id, log: &log };
+    let get = || -> Vec<_> {
+        let mut m = log.0.borrow_mut();
+        let n = m.drain(..);
+        n.collect()
+    };
+
+    {
+        let _x = (
+            d(
+                0,
+                d(
+                    1,
+                    if let Some(_) = d(2, Some(true)).extra && let DropLogger { .. } = d(3, None) {
+                        None
+                    } else {
+                        Some(true)
+                    }
+                ).extra
+            ),
+            d(4, None),
+            &d(5, None),
+            d(6, None),
+            if let DropLogger { .. } = d(7, None) && let DropLogger { .. } = d(8, None) {
+                d(9, None)
+            }
+            else {
+                // 10 is not constructed
+                d(10, None)
+            }
+        );
+        assert_eq!(get(), vec![3, 8, 7, 1, 2]);
+    }
+    assert_eq!(get(), vec![0, 4, 6, 9, 5]);
+
+    let _ = std::panic::catch_unwind(|| {
+        (
+            d(
+                11,
+                d(
+                    12,
+                    if let Some(_) = d(13, Some(true)).extra
+                        && let DropLogger { .. } = d(14, None)
+                    {
+                        None
+                    } else {
+                        Some(true)
+                    }
+                ).extra
+            ),
+            d(15, None),
+            &d(16, None),
+            d(17, None),
+            if let DropLogger { .. } = d(18, None) && let DropLogger { .. } = d(19, None) {
+                d(20, None)
+            }
+            else {
+                // 10 is not constructed
+                d(21, None)
+            },
+            panic::panic_any(InjectedFailure)
+        );
+    });
+    assert_eq!(get(), vec![14, 19, 20, 17, 15, 11, 18, 16, 12, 13]);
+}
diff --git a/src/test/ui/parser/recover-assoc-const-constraint.rs b/src/test/ui/parser/recover-assoc-const-constraint.rs
index 06be3cdcc1a..1453e6cb5cd 100644
--- a/src/test/ui/parser/recover-assoc-const-constraint.rs
+++ b/src/test/ui/parser/recover-assoc-const-constraint.rs
@@ -1,7 +1,9 @@
 #[cfg(FALSE)]
 fn syntax() {
-    bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
-    bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
+    bar::<Item = 42>();
+    //~^ ERROR associated const equality is incomplete
+    bar::<Item = { 42 }>();
+    //~^ ERROR associated const equality is incomplete
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/recover-assoc-const-constraint.stderr b/src/test/ui/parser/recover-assoc-const-constraint.stderr
index c6733b33faa..2d36ce4e986 100644
--- a/src/test/ui/parser/recover-assoc-const-constraint.stderr
+++ b/src/test/ui/parser/recover-assoc-const-constraint.stderr
@@ -1,20 +1,21 @@
-error: cannot constrain an associated constant to a value
+error[E0658]: associated const equality is incomplete
   --> $DIR/recover-assoc-const-constraint.rs:3:11
    |
 LL |     bar::<Item = 42>();
-   |           ----^^^--
-   |           |      |
-   |           |      ...cannot be constrained to this value
-   |           this associated constant...
+   |           ^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
 
-error: cannot constrain an associated constant to a value
-  --> $DIR/recover-assoc-const-constraint.rs:4:11
+error[E0658]: associated const equality is incomplete
+  --> $DIR/recover-assoc-const-constraint.rs:5:11
    |
 LL |     bar::<Item = { 42 }>();
-   |           ----^^^------
-   |           |      |
-   |           |      ...cannot be constrained to this value
-   |           this associated constant...
+   |           ^^^^^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/pattern/issue-82290.rs b/src/test/ui/pattern/issue-82290.rs
deleted file mode 100644
index d8da0ac8aa6..00000000000
--- a/src/test/ui/pattern/issue-82290.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// check-pass
-
-#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
-
-fn main() {
-    if true && let x = 1 { //~ WARN irrefutable `let` pattern
-        let _ = x;
-    }
-}
diff --git a/src/test/ui/pattern/issue-82290.stderr b/src/test/ui/pattern/issue-82290.stderr
deleted file mode 100644
index 0a3cf2c794f..00000000000
--- a/src/test/ui/pattern/issue-82290.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-82290.rs:3:12
-   |
-LL | #![feature(let_chains)]
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
-warning: irrefutable `let` pattern
-  --> $DIR/issue-82290.rs:6:16
-   |
-LL |     if true && let x = 1 {
-   |                ^^^^^^^^^
-   |
-   = note: `#[warn(irrefutable_let_patterns)]` on by default
-   = note: this pattern will always match, so the `let` is useless
-   = help: consider removing `let`
-
-warning: 2 warnings emitted
-
diff --git a/src/test/ui/resolve/resolve-hint-macro.fixed b/src/test/ui/resolve/resolve-hint-macro.fixed
new file mode 100644
index 00000000000..54e01608498
--- /dev/null
+++ b/src/test/ui/resolve/resolve-hint-macro.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+fn main() {
+    assert_eq!(1, 1);
+    //~^ ERROR expected function, found macro `assert_eq`
+    assert_eq! { 1, 1 };
+    //~^ ERROR expected struct, variant or union type, found macro `assert_eq`
+    //~| ERROR expected identifier, found `1`
+    //~| ERROR expected identifier, found `1`
+    assert![true];
+    //~^ ERROR expected value, found macro `assert`
+}
diff --git a/src/test/ui/resolve/resolve-hint-macro.rs b/src/test/ui/resolve/resolve-hint-macro.rs
index 5532c8b90e3..f16e8c07553 100644
--- a/src/test/ui/resolve/resolve-hint-macro.rs
+++ b/src/test/ui/resolve/resolve-hint-macro.rs
@@ -1,4 +1,11 @@
+// run-rustfix
 fn main() {
     assert_eq(1, 1);
     //~^ ERROR expected function, found macro `assert_eq`
+    assert_eq { 1, 1 };
+    //~^ ERROR expected struct, variant or union type, found macro `assert_eq`
+    //~| ERROR expected identifier, found `1`
+    //~| ERROR expected identifier, found `1`
+    assert[true];
+    //~^ ERROR expected value, found macro `assert`
 }
diff --git a/src/test/ui/resolve/resolve-hint-macro.stderr b/src/test/ui/resolve/resolve-hint-macro.stderr
index 78d77678083..bc69ddd8ffe 100644
--- a/src/test/ui/resolve/resolve-hint-macro.stderr
+++ b/src/test/ui/resolve/resolve-hint-macro.stderr
@@ -1,5 +1,21 @@
+error: expected identifier, found `1`
+  --> $DIR/resolve-hint-macro.rs:5:17
+   |
+LL |     assert_eq { 1, 1 };
+   |     ---------   ^ expected identifier
+   |     |
+   |     while parsing this struct
+
+error: expected identifier, found `1`
+  --> $DIR/resolve-hint-macro.rs:5:20
+   |
+LL |     assert_eq { 1, 1 };
+   |     ---------      ^ expected identifier
+   |     |
+   |     while parsing this struct
+
 error[E0423]: expected function, found macro `assert_eq`
-  --> $DIR/resolve-hint-macro.rs:2:5
+  --> $DIR/resolve-hint-macro.rs:3:5
    |
 LL |     assert_eq(1, 1);
    |     ^^^^^^^^^ not a function
@@ -9,6 +25,29 @@ help: use `!` to invoke the macro
 LL |     assert_eq!(1, 1);
    |              +
 
-error: aborting due to previous error
+error[E0574]: expected struct, variant or union type, found macro `assert_eq`
+  --> $DIR/resolve-hint-macro.rs:5:5
+   |
+LL |     assert_eq { 1, 1 };
+   |     ^^^^^^^^^ not a struct, variant or union type
+   |
+help: use `!` to invoke the macro
+   |
+LL |     assert_eq! { 1, 1 };
+   |              +
+
+error[E0423]: expected value, found macro `assert`
+  --> $DIR/resolve-hint-macro.rs:9:5
+   |
+LL |     assert[true];
+   |     ^^^^^^ not a value
+   |
+help: use `!` to invoke the macro
+   |
+LL |     assert![true];
+   |           +
+
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0423`.
+Some errors have detailed explanations: E0423, E0574.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
index 2a2c0be5263..34d2d84da93 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
@@ -8,36 +8,36 @@ fn _if_let_guard() {
         //~^ ERROR `if let` guards are experimental
 
         () if (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (((let 0 = 1))) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if true && let 0 = 1 => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && true => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && true => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if true && (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
-        //~^ ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
         _ => {}
     }
 }
@@ -52,9 +52,9 @@ fn _macros() {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR `let` expressions in this position are experimental
+    //~^ ERROR `let` expressions in this position are unstable
     use_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental
+    //~^ ERROR `let` expressions in this position are unstable
     match () {
         #[cfg(FALSE)]
         () if let 0 = 1 => {}
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
index bedcdcb019b..0cda6ba9a99 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
@@ -27,7 +27,7 @@ LL |         () if let 0 = 1 => {}
    = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:10:16
    |
 LL |         () if (let 0 = 1) => {}
@@ -35,9 +35,8 @@ LL |         () if (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:13:18
    |
 LL |         () if (((let 0 = 1))) => {}
@@ -45,9 +44,8 @@ LL |         () if (((let 0 = 1))) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:16:23
    |
 LL |         () if true && let 0 = 1 => {}
@@ -55,9 +53,8 @@ LL |         () if true && let 0 = 1 => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:19:15
    |
 LL |         () if let 0 = 1 && true => {}
@@ -65,9 +62,8 @@ LL |         () if let 0 = 1 && true => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:22:16
    |
 LL |         () if (let 0 = 1) && true => {}
@@ -75,9 +71,8 @@ LL |         () if (let 0 = 1) && true => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:25:24
    |
 LL |         () if true && (let 0 = 1) => {}
@@ -85,9 +80,8 @@ LL |         () if true && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:28:16
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
@@ -95,9 +89,8 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:28:31
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
@@ -105,9 +98,8 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:15
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -115,9 +107,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:28
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -125,9 +116,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -135,9 +125,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:55
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -145,9 +134,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:68
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -155,9 +143,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:39:15
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
@@ -165,9 +152,8 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:54:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
@@ -175,9 +161,8 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:56:16
    |
 LL |     use_expr!((let 0 = 1));
@@ -185,7 +170,6 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
 error: aborting due to 19 previous errors
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
new file mode 100644
index 00000000000..708bcdd0aef
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let first = Some(1);
+    let second = Some(2);
+    let mut n = 0;
+    if let x = first && let y = second && 1 == 1 {
+        assert_eq!(x, first);
+        assert_eq!(y, second);
+        n = 1;
+    }
+    assert_eq!(n, 1);
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
index 710fdd57ed7..69bc189dd35 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 // compile-flags: -Z unpretty=expanded
 
 fn main() {
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
index 6052ea95d0f..e737ef26e9b 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
@@ -4,7 +4,7 @@
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 // compile-flags: -Z unpretty=expanded
 
 fn main() { if let 0 = 1 {} }
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
new file mode 100644
index 00000000000..a7e108d72d1
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
@@ -0,0 +1,20 @@
+fn and_chain() {
+    let z;
+    if true && { z = 3; true} && z == 3 {}
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn and_chain_2() {
+    let z;
+    true && { z = 3; true} && z == 3;
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn or_chain() {
+    let z;
+    if false || { z = 3; false} || z == 3 {}
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn main() {
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
new file mode 100644
index 00000000000..3c47040cc8c
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
@@ -0,0 +1,21 @@
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:3:34
+   |
+LL |     if true && { z = 3; true} && z == 3 {}
+   |                                  ^ use of possibly-uninitialized `z`
+
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:9:31
+   |
+LL |     true && { z = 3; true} && z == 3;
+   |                               ^ use of possibly-uninitialized `z`
+
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:15:36
+   |
+LL |     if false || { z = 3; false} || z == 3 {}
+   |                                    ^ use of possibly-uninitialized `z`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
index b0b3464c610..5b2693d07a7 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -18,7 +18,6 @@
 // To that end, we check some positions which is not part of the language above.
 
 #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
-//~^ WARN the feature `let_chains` is incomplete
 
 #![allow(irrefutable_let_patterns)]
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 1433a16d727..4c830554d43 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:233:9
+  --> $DIR/disallowed-positions.rs:232:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:30:9
+  --> $DIR/disallowed-positions.rs:29:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -19,7 +19,7 @@ LL |     if &let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     if !let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:34:9
+  --> $DIR/disallowed-positions.rs:33:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -37,7 +37,7 @@ LL |     if *let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:36:9
+  --> $DIR/disallowed-positions.rs:35:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -46,7 +46,7 @@ LL |     if -let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:44:9
+  --> $DIR/disallowed-positions.rs:43:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -55,7 +55,7 @@ LL |     if (let 0 = 0)? {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:48:16
+  --> $DIR/disallowed-positions.rs:47:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     if true || let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:49:17
+  --> $DIR/disallowed-positions.rs:48:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     if (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:50:25
+  --> $DIR/disallowed-positions.rs:49:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -82,7 +82,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:51:25
+  --> $DIR/disallowed-positions.rs:50:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -91,7 +91,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:54:12
+  --> $DIR/disallowed-positions.rs:53:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     if x = let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:57:15
+  --> $DIR/disallowed-positions.rs:56:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     if true..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:59:11
+  --> $DIR/disallowed-positions.rs:58:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -118,7 +118,7 @@ LL |     if ..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:61:9
+  --> $DIR/disallowed-positions.rs:60:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -127,7 +127,7 @@ LL |     if (let 0 = 0).. {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:65:8
+  --> $DIR/disallowed-positions.rs:64:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:69:8
+  --> $DIR/disallowed-positions.rs:68:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:76:8
+  --> $DIR/disallowed-positions.rs:75:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,7 +154,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:84:8
+  --> $DIR/disallowed-positions.rs:83:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:90:19
+  --> $DIR/disallowed-positions.rs:89:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
@@ -172,7 +172,7 @@ LL |     if let true = let true = true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:94:12
+  --> $DIR/disallowed-positions.rs:93:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -181,7 +181,7 @@ LL |     while &let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:12
+  --> $DIR/disallowed-positions.rs:96:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -190,7 +190,7 @@ LL |     while !let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:98:12
+  --> $DIR/disallowed-positions.rs:97:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -199,7 +199,7 @@ LL |     while *let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:100:12
+  --> $DIR/disallowed-positions.rs:99:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -208,7 +208,7 @@ LL |     while -let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:108:12
+  --> $DIR/disallowed-positions.rs:107:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -217,7 +217,7 @@ LL |     while (let 0 = 0)? {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:112:19
+  --> $DIR/disallowed-positions.rs:111:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
@@ -226,7 +226,7 @@ LL |     while true || let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:113:20
+  --> $DIR/disallowed-positions.rs:112:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -235,7 +235,7 @@ LL |     while (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:114:28
+  --> $DIR/disallowed-positions.rs:113:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -244,7 +244,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:115:28
+  --> $DIR/disallowed-positions.rs:114:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -253,7 +253,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:118:15
+  --> $DIR/disallowed-positions.rs:117:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
@@ -262,7 +262,7 @@ LL |     while x = let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:121:18
+  --> $DIR/disallowed-positions.rs:120:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -271,7 +271,7 @@ LL |     while true..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:123:14
+  --> $DIR/disallowed-positions.rs:122:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -280,7 +280,7 @@ LL |     while ..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:125:12
+  --> $DIR/disallowed-positions.rs:124:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -289,7 +289,7 @@ LL |     while (let 0 = 0).. {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:129:11
+  --> $DIR/disallowed-positions.rs:128:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -298,7 +298,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:133:11
+  --> $DIR/disallowed-positions.rs:132:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -307,7 +307,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:140:11
+  --> $DIR/disallowed-positions.rs:139:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -316,7 +316,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:148:11
+  --> $DIR/disallowed-positions.rs:147:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -325,7 +325,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:154:22
+  --> $DIR/disallowed-positions.rs:153:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
@@ -334,7 +334,7 @@ LL |     while let true = let true = true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:168:6
+  --> $DIR/disallowed-positions.rs:167:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
@@ -343,7 +343,7 @@ LL |     &let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:170:6
+  --> $DIR/disallowed-positions.rs:169:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
@@ -352,7 +352,7 @@ LL |     !let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:171:6
+  --> $DIR/disallowed-positions.rs:170:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
@@ -361,7 +361,7 @@ LL |     *let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:173:6
+  --> $DIR/disallowed-positions.rs:172:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
@@ -370,7 +370,7 @@ LL |     -let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:181:6
+  --> $DIR/disallowed-positions.rs:180:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
@@ -379,7 +379,7 @@ LL |     (let 0 = 0)?;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:185:13
+  --> $DIR/disallowed-positions.rs:184:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
@@ -388,7 +388,7 @@ LL |     true || let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:186:14
+  --> $DIR/disallowed-positions.rs:185:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
@@ -397,7 +397,7 @@ LL |     (true || let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:187:22
+  --> $DIR/disallowed-positions.rs:186:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
@@ -406,7 +406,7 @@ LL |     true && (true || let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:190:9
+  --> $DIR/disallowed-positions.rs:189:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
@@ -415,7 +415,7 @@ LL |     x = let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:192:12
+  --> $DIR/disallowed-positions.rs:191:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
@@ -424,7 +424,7 @@ LL |     true..(let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:193:8
+  --> $DIR/disallowed-positions.rs:192:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
@@ -433,7 +433,7 @@ LL |     ..(let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:194:6
+  --> $DIR/disallowed-positions.rs:193:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
@@ -442,7 +442,7 @@ LL |     (let 0 = 0)..;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:196:6
+  --> $DIR/disallowed-positions.rs:195:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -451,7 +451,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:200:6
+  --> $DIR/disallowed-positions.rs:199:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -460,7 +460,7 @@ LL |     (let true = let true = true);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:204:6
+  --> $DIR/disallowed-positions.rs:203:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
@@ -469,7 +469,7 @@ LL |     &let 0 = 0
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:215:17
+  --> $DIR/disallowed-positions.rs:214:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -478,7 +478,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:219:17
+  --> $DIR/disallowed-positions.rs:218:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -487,7 +487,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:223:17
+  --> $DIR/disallowed-positions.rs:222:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -496,7 +496,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:233:17
+  --> $DIR/disallowed-positions.rs:232:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -504,17 +504,8 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if`- and `while`-expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/disallowed-positions.rs:20:12
-   |
-LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:30:8
+  --> $DIR/disallowed-positions.rs:29:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -526,19 +517,19 @@ LL +     if let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:34:8
+  --> $DIR/disallowed-positions.rs:33:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:36:8
+  --> $DIR/disallowed-positions.rs:35:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:44:8
+  --> $DIR/disallowed-positions.rs:43:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -546,7 +537,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:44:19
+  --> $DIR/disallowed-positions.rs:43:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -563,7 +554,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:54:8
+  --> $DIR/disallowed-positions.rs:53:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -574,7 +565,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:57:8
+  --> $DIR/disallowed-positions.rs:56:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -583,7 +574,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:59:8
+  --> $DIR/disallowed-positions.rs:58:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -592,7 +583,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:61:8
+  --> $DIR/disallowed-positions.rs:60:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -601,7 +592,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -612,7 +603,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:65:8
+  --> $DIR/disallowed-positions.rs:64:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -621,7 +612,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:69:12
+  --> $DIR/disallowed-positions.rs:68:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -632,7 +623,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:69:8
+  --> $DIR/disallowed-positions.rs:68:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -641,7 +632,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -652,16 +643,16 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:41
+  --> $DIR/disallowed-positions.rs:75:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:76:41: 76:48]`
+           found closure `[closure@$DIR/disallowed-positions.rs:75:41: 75:48]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:8
+  --> $DIR/disallowed-positions.rs:75:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -670,7 +661,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:12
+  --> $DIR/disallowed-positions.rs:83:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -681,13 +672,13 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:44
+  --> $DIR/disallowed-positions.rs:83:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:8
+  --> $DIR/disallowed-positions.rs:83:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -696,7 +687,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:40:20
+  --> $DIR/disallowed-positions.rs:39:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -704,7 +695,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:94:11
+  --> $DIR/disallowed-positions.rs:93:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -716,19 +707,19 @@ LL +     while let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:98:11
+  --> $DIR/disallowed-positions.rs:97:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:100:11
+  --> $DIR/disallowed-positions.rs:99:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:108:11
+  --> $DIR/disallowed-positions.rs:107:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -736,7 +727,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:108:22
+  --> $DIR/disallowed-positions.rs:107:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -753,7 +744,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:118:11
+  --> $DIR/disallowed-positions.rs:117:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -764,7 +755,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:121:11
+  --> $DIR/disallowed-positions.rs:120:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -773,7 +764,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:123:11
+  --> $DIR/disallowed-positions.rs:122:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -782,7 +773,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:125:11
+  --> $DIR/disallowed-positions.rs:124:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -791,7 +782,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:15
+  --> $DIR/disallowed-positions.rs:128:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -802,7 +793,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:11
+  --> $DIR/disallowed-positions.rs:128:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -811,7 +802,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:133:15
+  --> $DIR/disallowed-positions.rs:132:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -822,7 +813,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:133:11
+  --> $DIR/disallowed-positions.rs:132:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -831,7 +822,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:15
+  --> $DIR/disallowed-positions.rs:139:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -842,16 +833,16 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:44
+  --> $DIR/disallowed-positions.rs:139:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:140:44: 140:51]`
+           found closure `[closure@$DIR/disallowed-positions.rs:139:44: 139:51]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:11
+  --> $DIR/disallowed-positions.rs:139:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -860,7 +851,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:15
+  --> $DIR/disallowed-positions.rs:147:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -871,13 +862,13 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:47
+  --> $DIR/disallowed-positions.rs:147:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:11
+  --> $DIR/disallowed-positions.rs:147:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -886,7 +877,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:104:23
+  --> $DIR/disallowed-positions.rs:103:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -894,19 +885,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:171:5
+  --> $DIR/disallowed-positions.rs:170:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:173:5
+  --> $DIR/disallowed-positions.rs:172:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:181:5
+  --> $DIR/disallowed-positions.rs:180:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -914,7 +905,7 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:181:16
+  --> $DIR/disallowed-positions.rs:180:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -931,7 +922,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:196:10
+  --> $DIR/disallowed-positions.rs:195:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -942,7 +933,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:204:5
+  --> $DIR/disallowed-positions.rs:203:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -951,14 +942,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:177:17
+  --> $DIR/disallowed-positions.rs:176:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 103 previous errors; 1 warning emitted
+error: aborting due to 103 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
index 2b4259e9dc1..53fec8316e7 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
@@ -12,79 +12,79 @@ fn _if() {
     if let 0 = 1 {} // Stable!
 
     if (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     if let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
 
 fn _while() {
     while let 0 = 1 {} // Stable!
 
     while (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     while let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
 
 fn _macros() {
     macro_rules! noop_expr { ($e:expr) => {}; }
 
     noop_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     macro_rules! use_expr {
         ($e:expr) => {
@@ -93,11 +93,11 @@ fn _macros() {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     use_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     #[cfg(FALSE)] (let 0 = 1);
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     use_expr!(let 0 = 1);
     //~^ ERROR no rules expected the token `let`
     // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
index 180eee0cadf..458826498fe 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
@@ -7,7 +7,7 @@ LL |     macro_rules! use_expr {
 LL |     use_expr!(let 0 = 1);
    |               ^^^ no rules expected this token in macro call
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:14:9
    |
 LL |     if (let 0 = 1) {}
@@ -15,9 +15,8 @@ LL |     if (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:17:11
    |
 LL |     if (((let 0 = 1))) {}
@@ -25,9 +24,8 @@ LL |     if (((let 0 = 1))) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:20:16
    |
 LL |     if true && let 0 = 1 {}
@@ -35,9 +33,8 @@ LL |     if true && let 0 = 1 {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:23:8
    |
 LL |     if let 0 = 1 && true {}
@@ -45,9 +42,8 @@ LL |     if let 0 = 1 && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:26:9
    |
 LL |     if (let 0 = 1) && true {}
@@ -55,9 +51,8 @@ LL |     if (let 0 = 1) && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:29:17
    |
 LL |     if true && (let 0 = 1) {}
@@ -65,9 +60,8 @@ LL |     if true && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
@@ -75,9 +69,8 @@ LL |     if (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
@@ -85,9 +78,8 @@ LL |     if (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:8
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -95,9 +87,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:21
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -105,9 +96,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -115,9 +105,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -125,9 +114,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -135,9 +123,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:43:8
    |
 LL |     if let Range { start: _, end: _ } = (true..true) && false {}
@@ -145,9 +132,8 @@ LL |     if let Range { start: _, end: _ } = (true..true) && false {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:50:12
    |
 LL |     while (let 0 = 1) {}
@@ -155,9 +141,8 @@ LL |     while (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:53:14
    |
 LL |     while (((let 0 = 1))) {}
@@ -165,9 +150,8 @@ LL |     while (((let 0 = 1))) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:56:19
    |
 LL |     while true && let 0 = 1 {}
@@ -175,9 +159,8 @@ LL |     while true && let 0 = 1 {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:59:11
    |
 LL |     while let 0 = 1 && true {}
@@ -185,9 +168,8 @@ LL |     while let 0 = 1 && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:62:12
    |
 LL |     while (let 0 = 1) && true {}
@@ -195,9 +177,8 @@ LL |     while (let 0 = 1) && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:65:20
    |
 LL |     while true && (let 0 = 1) {}
@@ -205,9 +186,8 @@ LL |     while true && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:68:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
@@ -215,9 +195,8 @@ LL |     while (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:68:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
@@ -225,9 +204,8 @@ LL |     while (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:11
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -235,9 +213,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:24
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -245,9 +222,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -255,9 +231,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -265,9 +240,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -275,9 +249,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:79:11
    |
 LL |     while let Range { start: _, end: _ } = (true..true) && false {}
@@ -285,9 +258,8 @@ LL |     while let Range { start: _, end: _ } = (true..true) && false {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:99:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
@@ -295,9 +267,8 @@ LL |     #[cfg(FALSE)] (let 0 = 1);
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:86:17
    |
 LL |     noop_expr!((let 0 = 1));
@@ -305,9 +276,8 @@ LL |     noop_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:95:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
@@ -315,9 +285,8 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:97:16
    |
 LL |     use_expr!((let 0 = 1));
@@ -325,7 +294,6 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
 error: aborting due to 33 previous errors
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
new file mode 100644
index 00000000000..945c665e35d
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
@@ -0,0 +1,37 @@
+// check-pass
+
+#![feature(if_let_guard, let_chains)]
+
+use std::ops::Range;
+
+fn main() {
+    let opt = Some(None..Some(1));
+
+    if let first = &opt && let Some(ref second) = first && let None = second.start {
+    }
+    if let Some(ref first) = opt && let second = first && let _third = second {
+    }
+    if let Some(ref first) = opt
+        && let Range { start: local_start, end: _ } = first
+        && let None = local_start {
+    }
+
+    match opt {
+        Some(ref first) if let second = first && let _third = second => {},
+        _ => {}
+    }
+    match opt {
+        Some(ref first) if let Range { start: local_start, end: _ } = first
+            && let None = local_start => {},
+        _ => {}
+    }
+
+    while let first = &opt && let Some(ref second) = first && let None = second.start {
+    }
+    while let Some(ref first) = opt && let second = first && let _third = second {
+    }
+    while let Some(ref first) = opt
+        && let Range { start: local_start, end: _ } = first
+        && let None = local_start {
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs b/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs
new file mode 100644
index 00000000000..3eb8a9ad060
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+pub enum UnOp {
+    Not(Vec<()>),
+}
+
+pub fn foo() {
+    if let Some(x) = None {
+        match x {
+            UnOp::Not(_) => {}
+        }
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs
new file mode 100644
index 00000000000..6b7d8835650
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let x = Some(vec!["test"]);
+
+    if let Some(v) = x && v.is_empty() {
+        println!("x == Some([])");
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs
new file mode 100644
index 00000000000..7c7e31f4db4
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let opt = Some("foo bar");
+
+    if true && let Some(x) = opt {
+        println!("{}", x);
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs b/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs
new file mode 100644
index 00000000000..6b91c455e0e
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+fn main() {
+    loop {
+        // [1][0] should leave top scope
+        if true && [1][0] == 1 && true {
+        }
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
new file mode 100644
index 00000000000..e061174f667
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
@@ -0,0 +1,49 @@
+// run-pass
+
+#![feature(if_let_guard, let_chains)]
+
+fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    if let Some(first) = opt
+        && let Some(second) = first
+        && let Some(third) = second
+        && third == value
+    {
+        true
+    }
+    else {
+        false
+    }
+}
+
+fn check_let_guard(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    match opt {
+        Some(first) if let Some(second) = first && let Some(third) = second && third == value => {
+            true
+        }
+        _ => {
+            false
+        }
+    }
+}
+
+fn check_while_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    while let Some(first) = opt
+        && let Some(second) = first
+        && let Some(third) = second
+        && third == value
+    {
+        return true;
+    }
+    false
+}
+
+fn main() {
+    assert_eq!(check_if_let(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_if_let(Some(Some(Some(1))), 9), false);
+
+    assert_eq!(check_let_guard(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_let_guard(Some(Some(Some(1))), 9), false);
+
+    assert_eq!(check_while_let(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_while_let(Some(Some(Some(1))), 9), false);
+}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
index 0ab994ecd45..2a15b1d799f 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
@@ -1,4 +1,4 @@
-// only-windows-msvc
+// only-windows
 #![feature(raw_dylib)]
 //~^ WARN the feature `raw_dylib` is incomplete
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs
index d02bebc9d61..13c9aa01e34 100644
--- a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs
@@ -1,4 +1,5 @@
-// only-i686-pc-windows-msvc
+// only-x86
+// only-windows
 // compile-flags: --crate-type lib --emit link
 #![allow(clashing_extern_declarations)]
 #![feature(raw_dylib)]
diff --git a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
index a9cfd6b23f9..93ca8f4d8d4 100644
--- a/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
@@ -1,5 +1,5 @@
 warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/multiple-declarations.rs:4:12
+  --> $DIR/multiple-declarations.rs:5:12
    |
 LL | #![feature(raw_dylib)]
    |            ^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![feature(raw_dylib)]
    = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
 
 error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions
-  --> $DIR/multiple-declarations.rs:14:9
+  --> $DIR/multiple-declarations.rs:15:9
    |
 LL |         fn f(x: i32);
    |         ^^^^^^^^^^^^^
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs
deleted file mode 100644
index e9690f03f45..00000000000
--- a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// only-windows-gnu
-// check-pass
-// compile-flags: --crate-type lib
-#![feature(raw_dylib)]
-//~^ WARNING: the feature `raw_dylib` is incomplete
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-extern "C" {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr
deleted file mode 100644
index 6e24112b3c3..00000000000
--- a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-dylib-msvc-only.rs:4:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
-warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-  --> $DIR/raw-dylib-msvc-only.rs:6:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: 2 warnings emitted
-
diff --git a/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs
index e5a5ac2eb2b..dc647fd63f5 100644
--- a/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs
@@ -1,4 +1,5 @@
-// only-x86_64-pc-windows-msvc
+// only-x86_64
+// only-windows
 // compile-flags: --crate-type lib --emit link
 #![allow(incomplete_features)]
 #![feature(raw_dylib)]
diff --git a/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr
index fc9008128ae..d8a2a6af9c1 100644
--- a/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr
@@ -1,5 +1,5 @@
 error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
-  --> $DIR/unsupported-abi.rs:7:5
+  --> $DIR/unsupported-abi.rs:8:5
    |
 LL |     fn f(x: i32);
    |     ^^^^^^^^^^^^^
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
index e6846fb4049..299a2d2f2d3 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
@@ -2,28 +2,25 @@ error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
    |
 LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-   |                          ----               ----   ^ ...but data from `f` is held across an await point here
-   |                          |                  |
-   |                          |                  this `async fn` implicitly returns an `impl Future<Output = &Foo>`
-   |                          this parameter and the returned future are declared with different lifetimes...
+   |                                    ----     ----   ^ ...but data from `f` is returned here
+   |                                    |
+   |                                    this parameter and the return type are declared with different lifetimes...
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82
    |
 LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |                          -----                        -----------------          ^ ...but data from `f` is held across an await point here
-   |                          |                            |
-   |                          |                            this `async fn` implicitly returns an `impl Future<Output = (Pin<&Foo>, &Foo)>`
-   |                          this parameter and the returned future are declared with different lifetimes...
+   |                                     ----              -----------------          ^ ...but data from `f` is returned here
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
    |
 LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-   |                                  -----                   ---   ^^^ ...but data from `arg` is held across an await point here
-   |                                  |                       |
-   |                                  |                       this `async fn` implicitly returns an `impl Future<Output = &()>`
-   |                                  this parameter and the returned future are declared with different lifetimes...
+   |                                               ------     ---   ^^^ ...but data from `arg` is returned here
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/self/elision/lt-ref-self-async.stderr b/src/test/ui/self/elision/lt-ref-self-async.stderr
index 3221d270850..7448e8484b4 100644
--- a/src/test/ui/self/elision/lt-ref-self-async.stderr
+++ b/src/test/ui/self/elision/lt-ref-self-async.stderr
@@ -2,67 +2,61 @@ error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:13:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
-   |                       -----              ----
-   |                       |                  |
-   |                       |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                       this parameter and the returned future are declared with different lifetimes...
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:19:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                             -----              ----
-   |                             |                  |
-   |                             |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                             this parameter and the returned future are declared with different lifetimes...
+   |                                       ----     ----
+   |                                       |
+   |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:23:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:27:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:31:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                             -----                ----
-   |                                             |                    |
-   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:35:9
    |
 LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                         -----                ----
-   |                                         |                    |
-   |                                         |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                         this parameter and the returned future are declared with different lifetimes...
+   |                                                     ----     ----
+   |                                                     |
+   |                                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-self-async.stderr b/src/test/ui/self/elision/ref-mut-self-async.stderr
index b6ca986923d..6056cc46d3d 100644
--- a/src/test/ui/self/elision/ref-mut-self-async.stderr
+++ b/src/test/ui/self/elision/ref-mut-self-async.stderr
@@ -2,67 +2,61 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:13:9
    |
 LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
-   |                       ---------              ----
-   |                       |                      |
-   |                       |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                       this parameter and the returned future are declared with different lifetimes...
+   |                                     ----     ----
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:19:9
    |
 LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
-   |                             ---------              ----
-   |                             |                      |
-   |                             |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                             this parameter and the returned future are declared with different lifetimes...
+   |                                           ----     ----
+   |                                           |
+   |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:23:9
    |
 LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
-   |                                     ---------               ----
-   |                                     |                       |
-   |                                     |                       this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:27:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
-   |                                     ---------               ----
-   |                                     |                       |
-   |                                     |                       this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:31:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
-   |                                             ---------                ----
-   |                                             |                        |
-   |                                             |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:35:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
-   |                                             ---------                ----
-   |                                             |                        |
-   |                                             |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-struct-async.stderr b/src/test/ui/self/elision/ref-mut-struct-async.stderr
index eda15d76390..61034ae4d47 100644
--- a/src/test/ui/self/elision/ref-mut-struct-async.stderr
+++ b/src/test/ui/self/elision/ref-mut-struct-async.stderr
@@ -2,56 +2,51 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:13:9
    |
 LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
-   |                               -----------              ----
-   |                               |                        |
-   |                               |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                               this parameter and the returned future are declared with different lifetimes...
+   |                                               ----     ----
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:17:9
    |
 LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
-   |                                       -----------               ----
-   |                                       |                         |
-   |                                       |                         this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                        ----     ----
+   |                                                        |
+   |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:21:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
-   |                                       -----------               ----
-   |                                       |                         |
-   |                                       |                         this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                        ----     ----
+   |                                                        |
+   |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:25:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
-   |                                               -----------                ----
-   |                                               |                          |
-   |                                               |                          this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                               this parameter and the returned future are declared with different lifetimes...
+   |                                                                 ----     ----
+   |                                                                 |
+   |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:29:9
    |
 LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
-   |                                               -----------                ----
-   |                                               |                          |
-   |                                               |                          this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                               this parameter and the returned future are declared with different lifetimes...
+   |                                                                 ----     ----
+   |                                                                 |
+   |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/self/elision/ref-self-async.stderr b/src/test/ui/self/elision/ref-self-async.stderr
index b42caa88c6f..0eab16e685d 100644
--- a/src/test/ui/self/elision/ref-self-async.stderr
+++ b/src/test/ui/self/elision/ref-self-async.stderr
@@ -2,78 +2,71 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:23:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
-   |                       -----              ----
-   |                       |                  |
-   |                       |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                       this parameter and the returned future are declared with different lifetimes...
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:29:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                             -----              ----
-   |                             |                  |
-   |                             |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                             this parameter and the returned future are declared with different lifetimes...
+   |                                       ----     ----
+   |                                       |
+   |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:33:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:37:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:41:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                             -----                ----
-   |                                             |                    |
-   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:45:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                             -----                ----
-   |                                             |                    |
-   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:49:9
    |
 LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
-   |                                            -----                    ---
-   |                                            |                        |
-   |                                            |                        this `async fn` implicitly returns an `impl Future<Output = &u8>`
-   |                                            this parameter and the returned future are declared with different lifetimes...
+   |                                                             ---     ---
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/self/elision/ref-struct-async.stderr b/src/test/ui/self/elision/ref-struct-async.stderr
index 599becd3080..aa1d7453e83 100644
--- a/src/test/ui/self/elision/ref-struct-async.stderr
+++ b/src/test/ui/self/elision/ref-struct-async.stderr
@@ -2,56 +2,51 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:13:9
    |
 LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
-   |                               -------              ----
-   |                               |                    |
-   |                               |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                               this parameter and the returned future are declared with different lifetimes...
+   |                                           ----     ----
+   |                                           |
+   |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:17:9
    |
 LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
-   |                                       -------               ----
-   |                                       |                     |
-   |                                       |                     this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:21:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
-   |                                       -------               ----
-   |                                       |                     |
-   |                                       |                     this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:25:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
-   |                                               -------                ----
-   |                                               |                      |
-   |                                               |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                               this parameter and the returned future are declared with different lifetimes...
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:29:9
    |
 LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
-   |                                           -------                ----
-   |                                           |                      |
-   |                                           |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                           this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/self/self-infer.rs b/src/test/ui/self/self-infer.rs
index cc17d8f8e39..9839b8880e9 100644
--- a/src/test/ui/self/self-infer.rs
+++ b/src/test/ui/self/self-infer.rs
@@ -1,8 +1,8 @@
 struct S;
 
 impl S {
-    fn f(self: _) {} //~ERROR the type placeholder `_` is not allowed within types on item signatures for functions
-    fn g(self: &_) {} //~ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    fn f(self: _) {} //~ERROR the placeholder `_` is not allowed within types on item signatures for functions
+    fn g(self: &_) {} //~ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 fn main() {}
diff --git a/src/test/ui/self/self-infer.stderr b/src/test/ui/self/self-infer.stderr
index d3bf63efa40..4f9e3f21dca 100644
--- a/src/test/ui/self/self-infer.stderr
+++ b/src/test/ui/self/self-infer.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/self-infer.rs:4:16
    |
 LL |     fn f(self: _) {}
@@ -9,7 +9,7 @@ help: use type parameters instead
 LL |     fn f<T>(self: T) {}
    |         +++       ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/self-infer.rs:5:17
    |
 LL |     fn g(self: &_) {}
diff --git a/src/test/ui/simd/intrinsic/generic-as.rs b/src/test/ui/simd/intrinsic/generic-as.rs
new file mode 100644
index 00000000000..a975190a2fa
--- /dev/null
+++ b/src/test/ui/simd/intrinsic/generic-as.rs
@@ -0,0 +1,48 @@
+// run-pass
+
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_as<T, U>(x: T) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct V<T>([T; 2]);
+
+fn main() {
+    unsafe {
+        let u = V::<u32>([u32::MIN, u32::MAX]);
+        let i: V<i16> = simd_as(u);
+        assert_eq!(i.0[0], u.0[0] as i16);
+        assert_eq!(i.0[1], u.0[1] as i16);
+    }
+
+    unsafe {
+        let f = V::<f32>([f32::MIN, f32::MAX]);
+        let i: V<i16> = simd_as(f);
+        assert_eq!(i.0[0], f.0[0] as i16);
+        assert_eq!(i.0[1], f.0[1] as i16);
+    }
+
+    unsafe {
+        let f = V::<f32>([f32::MIN, f32::MAX]);
+        let u: V<u8> = simd_as(f);
+        assert_eq!(u.0[0], f.0[0] as u8);
+        assert_eq!(u.0[1], f.0[1] as u8);
+    }
+
+    unsafe {
+        let f = V::<f64>([f64::MIN, f64::MAX]);
+        let i: V<isize> = simd_as(f);
+        assert_eq!(i.0[0], f.0[0] as isize);
+        assert_eq!(i.0[1], f.0[1] as isize);
+    }
+
+    unsafe {
+        let f = V::<f64>([f64::MIN, f64::MAX]);
+        let u: V<usize> = simd_as(f);
+        assert_eq!(u.0[0], f.0[0] as usize);
+        assert_eq!(u.0[1], f.0[1] as usize);
+    }
+}
diff --git a/src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs b/src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs
new file mode 100644
index 00000000000..b9382310deb
--- /dev/null
+++ b/src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs
@@ -0,0 +1,21 @@
+// run-pass
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_cast<T, U>(x: T) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct V<T>([T; 4]);
+
+fn main() {
+    let u = V::<usize>([0, 1, 2, 3]);
+    let uu32: V<u32> = unsafe { simd_cast(u) };
+    let ui64: V<i64> = unsafe { simd_cast(u) };
+
+    for (u, (uu32, ui64)) in u.0.iter().zip(uu32.0.iter().zip(ui64.0.iter())) {
+        assert_eq!(*u as u32, *uu32);
+        assert_eq!(*u as i64, *ui64);
+    }
+}
diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
index 07d194476a5..ad51707070f 100644
--- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
+++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
@@ -1,4 +1,4 @@
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, (I,)), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, Ty((I,))), [])`
   --> $DIR/repeated_projection_type.rs:19:1
    |
 LL | / impl<I, V: Id<This = (I,)>> X for V {
diff --git a/src/test/ui/suggestions/unnamable-types.rs b/src/test/ui/suggestions/unnamable-types.rs
index 483f9bbb48c..f2485041d9b 100644
--- a/src/test/ui/suggestions/unnamable-types.rs
+++ b/src/test/ui/suggestions/unnamable-types.rs
@@ -8,14 +8,14 @@ const A = 5;
 //~| HELP: provide a type for the constant
 
 static B: _ = "abc";
-//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for static variables
 //~| NOTE: not allowed in type signatures
 //~| HELP: replace with the correct type
 
 
 // FIXME: this should also suggest a function pointer, as the closure is non-capturing
 const C: _ = || 42;
-//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for constants
 //~| NOTE: not allowed in type signatures
 //~| NOTE: however, the inferred type
 
diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr
index 3a489a6e943..6127446c83e 100644
--- a/src/test/ui/suggestions/unnamable-types.stderr
+++ b/src/test/ui/suggestions/unnamable-types.stderr
@@ -4,7 +4,7 @@ error: missing type for `const` item
 LL | const A = 5;
    |       ^ help: provide a type for the constant: `A: i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/unnamable-types.rs:10:11
    |
 LL | static B: _ = "abc";
@@ -13,7 +13,7 @@ LL | static B: _ = "abc";
    |           not allowed in type signatures
    |           help: replace with the correct type: `&str`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/unnamable-types.rs:17:10
    |
 LL | const C: _ = || 42;
diff --git a/src/test/ui/symbol-names/foreign-types.rs b/src/test/ui/symbol-names/foreign-types.rs
new file mode 100644
index 00000000000..8f5b07769ca
--- /dev/null
+++ b/src/test/ui/symbol-names/foreign-types.rs
@@ -0,0 +1,19 @@
+// build-fail
+// compile-flags: -C symbol-mangling-version=v0
+
+#![feature(extern_types)]
+#![feature(rustc_attrs)]
+
+extern "C" {
+    type ForeignType;
+}
+
+struct Check<T: ?Sized>(T);
+
+#[rustc_symbol_name]
+//~^ ERROR symbol-name(_RMCs
+//~| ERROR demangling(<foreign_types[
+//~| ERROR demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
+impl Check<ForeignType> {}
+
+fn main() {}
diff --git a/src/test/ui/symbol-names/foreign-types.stderr b/src/test/ui/symbol-names/foreign-types.stderr
new file mode 100644
index 00000000000..fcffdd2a8ec
--- /dev/null
+++ b/src/test/ui/symbol-names/foreign-types.stderr
@@ -0,0 +1,20 @@
+error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNvB<REF>_11ForeignTypeE)
+  --> $DIR/foreign-types.rs:13:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<foreign_types[HASH]::Check<foreign_types[HASH]::ForeignType>>)
+  --> $DIR/foreign-types.rs:13:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
+  --> $DIR/foreign-types.rs:13:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of.rs
new file mode 100644
index 00000000000..5ba2f5ce334
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of.rs
@@ -0,0 +1,44 @@
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(eq, neq)]
+trait Equal {
+    fn eq(&self, other: &Self) -> bool {
+        !self.neq(other)
+    }
+
+    fn neq(&self, other: &Self) -> bool {
+        !self.eq(other)
+    }
+}
+
+struct T0;
+struct T1;
+struct T2;
+struct T3;
+
+impl Equal for T0 {
+    fn eq(&self, _other: &Self) -> bool {
+        true
+    }
+}
+
+impl Equal for T1 {
+    fn neq(&self, _other: &Self) -> bool {
+        false
+    }
+}
+
+impl Equal for T2 {
+    fn eq(&self, _other: &Self) -> bool {
+        true
+    }
+
+    fn neq(&self, _other: &Self) -> bool {
+        false
+    }
+}
+
+impl Equal for T3 {}
+//~^ not all trait items implemented, missing one of: `eq`, `neq`
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of.stderr
new file mode 100644
index 00000000000..5a4dd1388b2
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of.stderr
@@ -0,0 +1,15 @@
+error[E0046]: not all trait items implemented, missing one of: `eq`, `neq`
+  --> $DIR/rustc_must_implement_one_of.rs:41:1
+   |
+LL | impl Equal for T3 {}
+   | ^^^^^^^^^^^^^^^^^ missing one of `eq`, `neq` in implementation
+   |
+note: required because of this annotation
+  --> $DIR/rustc_must_implement_one_of.rs:3:1
+   |
+LL | #[rustc_must_implement_one_of(eq, neq)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs
new file mode 100644
index 00000000000..56e8fcff0fc
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs
@@ -0,0 +1,19 @@
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(a, a)]
+//~^ Functions names are duplicated
+trait Trait {
+    fn a() {}
+}
+
+#[rustc_must_implement_one_of(b, a, a, c, b, c)]
+//~^ Functions names are duplicated
+//~| Functions names are duplicated
+//~| Functions names are duplicated
+trait Trait1 {
+    fn a() {}
+    fn b() {}
+    fn c() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr
new file mode 100644
index 00000000000..777beba6182
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr
@@ -0,0 +1,34 @@
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:3:31
+   |
+LL | #[rustc_must_implement_one_of(a, a)]
+   |                               ^  ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:34
+   |
+LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
+   |                                  ^  ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:31
+   |
+LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
+   |                               ^           ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:40
+   |
+LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
+   |                                        ^     ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.rs
new file mode 100644
index 00000000000..ec2995872de
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.rs
@@ -0,0 +1,13 @@
+#[rustc_must_implement_one_of(eq, neq)]
+//~^ the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
+trait Equal {
+    fn eq(&self, other: &Self) -> bool {
+        !self.neq(other)
+    }
+
+    fn neq(&self, other: &Self) -> bool {
+        !self.eq(other)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr
new file mode 100644
index 00000000000..228bc3e35c2
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr
@@ -0,0 +1,11 @@
+error[E0658]: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
+  --> $DIR/rustc_must_implement_one_of_gated.rs:1:1
+   |
+LL | #[rustc_must_implement_one_of(eq, neq)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs
new file mode 100644
index 00000000000..1089e5f9c4a
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs
@@ -0,0 +1,38 @@
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(a, b)]
+//~^ Function not found in this trait
+//~| Function not found in this trait
+trait Tr0 {}
+
+#[rustc_must_implement_one_of(a, b)]
+//~^ Function not found in this trait
+trait Tr1 {
+    fn a() {}
+}
+
+#[rustc_must_implement_one_of(a)]
+//~^ the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
+trait Tr2 {
+    fn a() {}
+}
+
+#[rustc_must_implement_one_of]
+//~^ malformed `rustc_must_implement_one_of` attribute input
+trait Tr3 {}
+
+#[rustc_must_implement_one_of(A, B)]
+trait Tr4 {
+    const A: u8 = 1; //~ Not a function
+
+    type B; //~ Not a function
+}
+
+#[rustc_must_implement_one_of(a, b)]
+trait Tr5 {
+    fn a(); //~ This function doesn't have a default implementation
+
+    fn b(); //~ This function doesn't have a default implementation
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr
new file mode 100644
index 00000000000..74a6dc8fec9
--- /dev/null
+++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr
@@ -0,0 +1,82 @@
+error: malformed `rustc_must_implement_one_of` attribute input
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:20:1
+   |
+LL | #[rustc_must_implement_one_of]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]`
+
+error: Function not found in this trait
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:31
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   |                               ^
+
+error: Function not found in this trait
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:34
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   |                                  ^
+
+error: Function not found in this trait
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:8:34
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   |                                  ^
+
+error: the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:14:1
+   |
+LL | #[rustc_must_implement_one_of(a)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Not a function
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:26:5
+   |
+LL |     const A: u8 = 1;
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:24:1
+   |
+LL | #[rustc_must_implement_one_of(A, B)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
+
+error: Not a function
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:28:5
+   |
+LL |     type B;
+   |     ^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:24:1
+   |
+LL | #[rustc_must_implement_one_of(A, B)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
+
+error: This function doesn't have a default implementation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:33:5
+   |
+LL |     fn a();
+   |     ^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:31:1
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: This function doesn't have a default implementation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:35:5
+   |
+LL |     fn b();
+   |     ^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:31:1
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/ui/transmute/transmute-imut-to-mut.rs b/src/test/ui/transmute/transmute-imut-to-mut.rs
index 8e34e0ae8c7..9f3f76c1ef3 100644
--- a/src/test/ui/transmute/transmute-imut-to-mut.rs
+++ b/src/test/ui/transmute/transmute-imut-to-mut.rs
@@ -4,5 +4,5 @@ use std::mem::transmute;
 
 fn main() {
     let _a: &mut u8 = unsafe { transmute(&1u8) };
-    //~^ ERROR mutating transmuted &mut T from &T may cause undefined behavior
+    //~^ ERROR transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
 }
diff --git a/src/test/ui/transmute/transmute-imut-to-mut.stderr b/src/test/ui/transmute/transmute-imut-to-mut.stderr
index d323c1a73b7..1e9dff3ce89 100644
--- a/src/test/ui/transmute/transmute-imut-to-mut.stderr
+++ b/src/test/ui/transmute/transmute-imut-to-mut.stderr
@@ -1,4 +1,4 @@
-error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
+error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
   --> $DIR/transmute-imut-to-mut.rs:6:32
    |
 LL |     let _a: &mut u8 = unsafe { transmute(&1u8) };
diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.rs b/src/test/ui/type-alias-impl-trait/issue-77179.rs
index 31c45a2093a..8d818d4a387 100644
--- a/src/test/ui/type-alias-impl-trait/issue-77179.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-77179.rs
@@ -5,7 +5,7 @@
 type Pointer<T> = impl std::ops::Deref<Target=T>;
 
 fn test() -> Pointer<_> {
-    //~^ ERROR: the type placeholder `_` is not allowed within types
+    //~^ ERROR: the placeholder `_` is not allowed within types
     Box::new(1)
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.stderr b/src/test/ui/type-alias-impl-trait/issue-77179.stderr
index 593aeeacb83..15205ba9b41 100644
--- a/src/test/ui/type-alias-impl-trait/issue-77179.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-77179.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-77179.rs:7:22
    |
 LL | fn test() -> Pointer<_> {
diff --git a/src/test/ui/typeck/issue-74086.rs b/src/test/ui/typeck/issue-74086.rs
index 1de9cd8007c..44ca256b051 100644
--- a/src/test/ui/typeck/issue-74086.rs
+++ b/src/test/ui/typeck/issue-74086.rs
@@ -1,4 +1,4 @@
 fn main() {
     static BUG: fn(_) -> u8 = |_| 8;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions [E0121]
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions [E0121]
 }
diff --git a/src/test/ui/typeck/issue-74086.stderr b/src/test/ui/typeck/issue-74086.stderr
index ac1752e17df..e7aea33758c 100644
--- a/src/test/ui/typeck/issue-74086.stderr
+++ b/src/test/ui/typeck/issue-74086.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/issue-74086.rs:2:20
    |
 LL |     static BUG: fn(_) -> u8 = |_| 8;
diff --git a/src/test/ui/typeck/issue-75883.rs b/src/test/ui/typeck/issue-75883.rs
index 0d1534df091..885acc48231 100644
--- a/src/test/ui/typeck/issue-75883.rs
+++ b/src/test/ui/typeck/issue-75883.rs
@@ -5,7 +5,7 @@ pub struct UI {}
 impl UI {
     pub fn run() -> Result<_> {
         //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied
-        //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+        //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types
         let mut ui = UI {};
         ui.interact();
 
@@ -14,7 +14,7 @@ impl UI {
 
     pub fn interact(&mut self) -> Result<_> {
         //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied
-        //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+        //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types
         unimplemented!();
     }
 }
diff --git a/src/test/ui/typeck/issue-75883.stderr b/src/test/ui/typeck/issue-75883.stderr
index 5e42c817e03..3861e0507f6 100644
--- a/src/test/ui/typeck/issue-75883.stderr
+++ b/src/test/ui/typeck/issue-75883.stderr
@@ -34,13 +34,13 @@ help: add missing generic argument
 LL |     pub fn interact(&mut self) -> Result<_, E> {
    |                                           +++
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-75883.rs:15:42
    |
 LL |     pub fn interact(&mut self) -> Result<_> {
    |                                          ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-75883.rs:6:28
    |
 LL |     pub fn run() -> Result<_> {
diff --git a/src/test/ui/typeck/issue-75889.stderr b/src/test/ui/typeck/issue-75889.stderr
index de4bdf4e6d9..1438f481ec7 100644
--- a/src/test/ui/typeck/issue-75889.stderr
+++ b/src/test/ui/typeck/issue-75889.stderr
@@ -1,10 +1,10 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constant items
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constant items
   --> $DIR/issue-75889.rs:3:24
    |
 LL | const FOO: dyn Fn() -> _ = "";
    |                        ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static items
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static items
   --> $DIR/issue-75889.rs:4:25
    |
 LL | static BOO: dyn Fn() -> _ = "";
diff --git a/src/test/ui/typeck/issue-80779.rs b/src/test/ui/typeck/issue-80779.rs
index 99a93b1863d..1624f6b7742 100644
--- a/src/test/ui/typeck/issue-80779.rs
+++ b/src/test/ui/typeck/issue-80779.rs
@@ -3,11 +3,11 @@
 pub struct T<'a>(&'a str);
 
 pub fn f<'a>(val: T<'a>) -> _ {
-    //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for return types
     g(val)
 }
 
 pub fn g(_: T<'static>) -> _ {}
-//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for return types
 
 fn main() {}
diff --git a/src/test/ui/typeck/issue-80779.stderr b/src/test/ui/typeck/issue-80779.stderr
index 5a695fecc29..2261ba61654 100644
--- a/src/test/ui/typeck/issue-80779.stderr
+++ b/src/test/ui/typeck/issue-80779.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80779.rs:10:28
    |
 LL | pub fn g(_: T<'static>) -> _ {}
@@ -7,7 +7,7 @@ LL | pub fn g(_: T<'static>) -> _ {}
    |                            not allowed in type signatures
    |                            help: replace with the correct return type: `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80779.rs:5:29
    |
 LL | pub fn f<'a>(val: T<'a>) -> _ {
diff --git a/src/test/ui/typeck/issue-81885.rs b/src/test/ui/typeck/issue-81885.rs
index 5117f250fe5..8935535fb7e 100644
--- a/src/test/ui/typeck/issue-81885.rs
+++ b/src/test/ui/typeck/issue-81885.rs
@@ -1,8 +1,8 @@
 const TEST4: fn() -> _ = 42;
-                  //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+                  //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn main() {
     const TEST5: fn() -> _ = 42;
-                      //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+                      //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 }
diff --git a/src/test/ui/typeck/issue-81885.stderr b/src/test/ui/typeck/issue-81885.stderr
index 8206156a618..3ff4375cd8d 100644
--- a/src/test/ui/typeck/issue-81885.stderr
+++ b/src/test/ui/typeck/issue-81885.stderr
@@ -1,10 +1,10 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/issue-81885.rs:1:22
    |
 LL | const TEST4: fn() -> _ = 42;
    |                      ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/issue-81885.rs:5:26
    |
 LL |     const TEST5: fn() -> _ = 42;
diff --git a/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr b/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr
index 7c5cf1082be..9376e8bcf80 100644
--- a/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr
+++ b/src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/issue-83621-placeholder-static-in-extern.rs:4:15
    |
 LL |     static x: _;
diff --git a/src/test/ui/typeck/issue-91450-inner-ty-error.rs b/src/test/ui/typeck/issue-91450-inner-ty-error.rs
index 0b942d6d94f..3c7c990d4e2 100644
--- a/src/test/ui/typeck/issue-91450-inner-ty-error.rs
+++ b/src/test/ui/typeck/issue-91450-inner-ty-error.rs
@@ -2,6 +2,6 @@
 // This test ensures that the compiler does not suggest `Foo<[type error]>` in diagnostic messages.
 
 fn foo() -> Option<_> {} //~ ERROR: [E0308]
-//~^ ERROR: the type placeholder `_` is not allowed
+//~^ ERROR: the placeholder `_` is not allowed
 
 fn main() {}
diff --git a/src/test/ui/typeck/issue-91450-inner-ty-error.stderr b/src/test/ui/typeck/issue-91450-inner-ty-error.stderr
index 314fe561803..32f4c8f6fdf 100644
--- a/src/test/ui/typeck/issue-91450-inner-ty-error.stderr
+++ b/src/test/ui/typeck/issue-91450-inner-ty-error.stderr
@@ -9,7 +9,7 @@ LL | fn foo() -> Option<_> {}
    = note:   expected enum `Option<_>`
            found unit type `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-91450-inner-ty-error.rs:4:20
    |
 LL | fn foo() -> Option<_> {}
diff --git a/src/test/ui/typeck/type-placeholder-fn-in-const.rs b/src/test/ui/typeck/type-placeholder-fn-in-const.rs
index f657bea1648..ab2e2d8c53a 100644
--- a/src/test/ui/typeck/type-placeholder-fn-in-const.rs
+++ b/src/test/ui/typeck/type-placeholder-fn-in-const.rs
@@ -2,13 +2,13 @@ struct MyStruct;
 
 trait Test {
     const TEST: fn() -> _;
-    //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for functions [E0121]
-    //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for constants [E0121]
+    //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121]
+    //~| ERROR: the placeholder `_` is not allowed within types on item signatures for constants [E0121]
 }
 
 impl Test for MyStruct {
     const TEST: fn() -> _ = 42;
-    //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for functions [E0121]
+    //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121]
 }
 
 fn main() {}
diff --git a/src/test/ui/typeck/type-placeholder-fn-in-const.stderr b/src/test/ui/typeck/type-placeholder-fn-in-const.stderr
index 62f4db8638f..e7b2e554a8d 100644
--- a/src/test/ui/typeck/type-placeholder-fn-in-const.stderr
+++ b/src/test/ui/typeck/type-placeholder-fn-in-const.stderr
@@ -1,16 +1,16 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/type-placeholder-fn-in-const.rs:4:25
    |
 LL |     const TEST: fn() -> _;
    |                         ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/type-placeholder-fn-in-const.rs:4:25
    |
 LL |     const TEST: fn() -> _;
    |                         ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/type-placeholder-fn-in-const.rs:10:25
    |
 LL |     const TEST: fn() -> _ = 42;
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs
index a3b75543510..ca0876be58d 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.rs
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs
@@ -5,67 +5,67 @@
 // inference by using the `_` type placeholder.
 
 fn test() -> _ { 5 }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
 fn test2() -> (_, _) { (5, 5) }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
 static TEST3: _ = "test";
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
 static TEST4: _ = 145;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
 static TEST5: (_, _) = (1, 2);
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
 fn test6(_: _) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test6_b<T>(_: _, _: T) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test7(x: _) { let _x: usize = x; }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test8(_f: fn() -> _) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
-//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+//~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 struct Test9;
 
 impl Test9 {
     fn test9(&self) -> _ { () }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn test10(&self, _x : _) { }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 fn test11(x: &usize) -> &_ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     &x
 }
 
 unsafe fn test12(x: *const usize) -> *const *const _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     &x
 }
 
 impl Clone for Test9 {
     fn clone(&self) -> _ { Test9 }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn clone_from(&mut self, other: _) { *self = Test9; }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 struct Test10 {
     a: _,
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
     b: (_, _),
 }
 
@@ -73,94 +73,94 @@ pub fn main() {
     static A = 42;
     //~^ ERROR missing type for `static` item
     static B: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
     static C: Option<_> = Some(42);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
     fn fn_test() -> _ { 5 }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn fn_test2() -> (_, _) { (5, 5) }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     static FN_TEST3: _ = "test";
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
     static FN_TEST4: _ = 145;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
     static FN_TEST5: (_, _) = (1, 2);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
     fn fn_test6(_: _) { }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
     fn fn_test7(x: _) { let _x: usize = x; }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
     fn fn_test8(_f: fn() -> _) { }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
-    //~^^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+    //~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
     struct FnTest9;
 
     impl FnTest9 {
         fn fn_test9(&self) -> _ { () }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
         fn fn_test10(&self, _x : _) { }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     }
 
     impl Clone for FnTest9 {
         fn clone(&self) -> _ { FnTest9 }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
         fn clone_from(&mut self, other: _) { *self = FnTest9; }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     }
 
     struct FnTest10 {
         a: _,
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
         b: (_, _),
     }
 
     fn fn_test11(_: _) -> (_, _) { panic!() }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     //~| ERROR type annotations needed
 
     fn fn_test12(x: i32) -> (_, _) { (x, x) }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn fn_test13(x: _) -> (i32, _) { (x, x) }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 }
 
 trait T {
     fn method_test1(&self, x: _);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn method_test2(&self, x: _) -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn method_test3(&self) -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn assoc_fn_test1(x: _);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn assoc_fn_test2(x: _) -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn assoc_fn_test3() -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 struct BadStruct<_>(_);
 //~^ ERROR expected identifier, found reserved identifier `_`
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
 trait BadTrait<_> {}
 //~^ ERROR expected identifier, found reserved identifier `_`
 impl BadTrait<_> for BadStruct<_> {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for implementations
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations
 
 fn impl_trait() -> impl BadTrait<_> {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for opaque types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
     unimplemented!()
 }
 
@@ -168,19 +168,19 @@ struct BadStruct1<_, _>(_);
 //~^ ERROR expected identifier, found reserved identifier `_`
 //~| ERROR expected identifier, found reserved identifier `_`
 //~| ERROR the name `_` is already used
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
 struct BadStruct2<_, T>(_, T);
 //~^ ERROR expected identifier, found reserved identifier `_`
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
 
 type X = Box<_>;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for type aliases
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for type aliases
 
 struct Struct;
 trait Trait<T> {}
 impl Trait<usize> for Struct {}
 type Y = impl Trait<_>;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for opaque types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
 fn foo() -> Y {
     Struct
 }
@@ -188,25 +188,25 @@ fn foo() -> Y {
 trait Qux {
     type A;
     type B = _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
     const C: _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
     const D: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
     // type E: _; // FIXME: make the parser propagate the existence of `B`
     type F: std::ops::Fn(_);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
 }
 impl Qux for Struct {
     type A = _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
     type B = _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
     const C: _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
     //~| ERROR associated constant in `impl` without body
     const D: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 }
 
 fn map<T>(_: fn() -> Option<&'static T>) -> Option<T> {
@@ -214,9 +214,9 @@ fn map<T>(_: fn() -> Option<&'static T>) -> Option<T> {
 }
 
 fn value() -> Option<&'static _> {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     Option::<&'static u8>::None
 }
 
 const _: Option<_> = map(value);
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
index e1f66afdacc..c07b96f9a97 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
@@ -44,7 +44,7 @@ LL | struct BadStruct1<_, _>(_);
    |                   |
    |                   first use of `_`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:7:14
    |
 LL | fn test() -> _ { 5 }
@@ -53,7 +53,7 @@ LL | fn test() -> _ { 5 }
    |              not allowed in type signatures
    |              help: replace with the correct return type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:10:16
    |
 LL | fn test2() -> (_, _) { (5, 5) }
@@ -63,7 +63,7 @@ LL | fn test2() -> (_, _) { (5, 5) }
    |               |not allowed in type signatures
    |               help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:13:15
    |
 LL | static TEST3: _ = "test";
@@ -72,7 +72,7 @@ LL | static TEST3: _ = "test";
    |               not allowed in type signatures
    |               help: replace with the correct type: `&str`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:16:15
    |
 LL | static TEST4: _ = 145;
@@ -81,13 +81,13 @@ LL | static TEST4: _ = 145;
    |               not allowed in type signatures
    |               help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:19:15
    |
 LL | static TEST5: (_, _) = (1, 2);
    |               ^^^^^^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:22:13
    |
 LL | fn test6(_: _) { }
@@ -98,7 +98,7 @@ help: use type parameters instead
 LL | fn test6<T>(_: T) { }
    |         +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:25:18
    |
 LL | fn test6_b<T>(_: _, _: T) { }
@@ -109,7 +109,7 @@ help: use type parameters instead
 LL | fn test6_b<T, U>(_: U, _: T) { }
    |             +++     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:28:30
    |
 LL | fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
@@ -120,7 +120,7 @@ help: use type parameters instead
 LL | fn test6_c<T, K, L, A, B, U>(_: U, _: (T, K, L, A, B)) { }
    |                         +++     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:31:13
    |
 LL | fn test7(x: _) { let _x: usize = x; }
@@ -131,7 +131,7 @@ help: use type parameters instead
 LL | fn test7<T>(x: T) { let _x: usize = x; }
    |         +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:34:22
    |
 LL | fn test8(_f: fn() -> _) { }
@@ -140,7 +140,7 @@ LL | fn test8(_f: fn() -> _) { }
    |                      not allowed in type signatures
    |                      help: use type parameters instead: `T`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:34:22
    |
 LL | fn test8(_f: fn() -> _) { }
@@ -151,7 +151,7 @@ help: use type parameters instead
 LL | fn test8<T>(_f: fn() -> T) { }
    |         +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:48:26
    |
 LL | fn test11(x: &usize) -> &_ {
@@ -160,7 +160,7 @@ LL | fn test11(x: &usize) -> &_ {
    |                         |not allowed in type signatures
    |                         help: replace with the correct return type: `&'static &'static usize`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:53:52
    |
 LL | unsafe fn test12(x: *const usize) -> *const *const _ {
@@ -169,7 +169,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ {
    |                                      |             not allowed in type signatures
    |                                      help: replace with the correct return type: `*const *const usize`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:67:8
    |
 LL |     a: _,
@@ -194,7 +194,7 @@ error: missing type for `static` item
 LL |     static A = 42;
    |            ^ help: provide a type for the static variable: `A: i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:75:15
    |
 LL |     static B: _ = 42;
@@ -203,13 +203,13 @@ LL |     static B: _ = 42;
    |               not allowed in type signatures
    |               help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:77:15
    |
 LL |     static C: Option<_> = Some(42);
    |               ^^^^^^^^^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:79:21
    |
 LL |     fn fn_test() -> _ { 5 }
@@ -218,7 +218,7 @@ LL |     fn fn_test() -> _ { 5 }
    |                     not allowed in type signatures
    |                     help: replace with the correct return type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:82:23
    |
 LL |     fn fn_test2() -> (_, _) { (5, 5) }
@@ -228,7 +228,7 @@ LL |     fn fn_test2() -> (_, _) { (5, 5) }
    |                      |not allowed in type signatures
    |                      help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:85:22
    |
 LL |     static FN_TEST3: _ = "test";
@@ -237,7 +237,7 @@ LL |     static FN_TEST3: _ = "test";
    |                      not allowed in type signatures
    |                      help: replace with the correct type: `&str`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:88:22
    |
 LL |     static FN_TEST4: _ = 145;
@@ -246,13 +246,13 @@ LL |     static FN_TEST4: _ = 145;
    |                      not allowed in type signatures
    |                      help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:91:22
    |
 LL |     static FN_TEST5: (_, _) = (1, 2);
    |                      ^^^^^^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:94:20
    |
 LL |     fn fn_test6(_: _) { }
@@ -263,7 +263,7 @@ help: use type parameters instead
 LL |     fn fn_test6<T>(_: T) { }
    |                +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:97:20
    |
 LL |     fn fn_test7(x: _) { let _x: usize = x; }
@@ -274,7 +274,7 @@ help: use type parameters instead
 LL |     fn fn_test7<T>(x: T) { let _x: usize = x; }
    |                +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:100:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
@@ -283,7 +283,7 @@ LL |     fn fn_test8(_f: fn() -> _) { }
    |                             not allowed in type signatures
    |                             help: use type parameters instead: `T`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:100:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
@@ -294,7 +294,7 @@ help: use type parameters instead
 LL |     fn fn_test8<T>(_f: fn() -> T) { }
    |                +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:123:12
    |
 LL |         a: _,
@@ -319,7 +319,7 @@ error[E0282]: type annotations needed
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                  ^ cannot infer type
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:128:28
    |
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
@@ -327,7 +327,7 @@ LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                            |
    |                            not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:132:30
    |
 LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
@@ -337,7 +337,7 @@ LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
    |                             |not allowed in type signatures
    |                             help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:135:33
    |
 LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
@@ -346,7 +346,7 @@ LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           |     not allowed in type signatures
    |                           help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:154:21
    |
 LL | struct BadStruct<_>(_);
@@ -357,7 +357,7 @@ help: use type parameters instead
 LL | struct BadStruct<T>(T);
    |                  ~  ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for implementations
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations
   --> $DIR/typeck_type_placeholder_item.rs:159:15
    |
 LL | impl BadTrait<_> for BadStruct<_> {}
@@ -370,13 +370,13 @@ help: use type parameters instead
 LL | impl<T> BadTrait<T> for BadStruct<T> {}
    |     +++          ~                ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for opaque types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
   --> $DIR/typeck_type_placeholder_item.rs:162:34
    |
 LL | fn impl_trait() -> impl BadTrait<_> {
    |                                  ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:167:25
    |
 LL | struct BadStruct1<_, _>(_);
@@ -387,7 +387,7 @@ help: use type parameters instead
 LL | struct BadStruct1<T, _>(T);
    |                   ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:172:25
    |
 LL | struct BadStruct2<_, T>(_, T);
@@ -398,19 +398,19 @@ help: use type parameters instead
 LL | struct BadStruct2<U, T>(U, T);
    |                   ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for type aliases
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
   --> $DIR/typeck_type_placeholder_item.rs:176:14
    |
 LL | type X = Box<_>;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for opaque types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
   --> $DIR/typeck_type_placeholder_item.rs:182:21
    |
 LL | type Y = impl Trait<_>;
    |                     ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:216:31
    |
 LL | fn value() -> Option<&'static _> {
@@ -419,7 +419,7 @@ LL | fn value() -> Option<&'static _> {
    |               |               not allowed in type signatures
    |               help: replace with the correct return type: `Option<&'static u8>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:221:10
    |
 LL | const _: Option<_> = map(value);
@@ -428,7 +428,7 @@ LL | const _: Option<_> = map(value);
    |          not allowed in type signatures
    |          help: replace with the correct type: `Option<u8>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:140:31
    |
 LL |     fn method_test1(&self, x: _);
@@ -439,7 +439,7 @@ help: use type parameters instead
 LL |     fn method_test1<T>(&self, x: T);
    |                    +++           ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:142:31
    |
 LL |     fn method_test2(&self, x: _) -> _;
@@ -452,7 +452,7 @@ help: use type parameters instead
 LL |     fn method_test2<T>(&self, x: T) -> T;
    |                    +++           ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:144:31
    |
 LL |     fn method_test3(&self) -> _;
@@ -463,7 +463,7 @@ help: use type parameters instead
 LL |     fn method_test3<T>(&self) -> T;
    |                    +++           ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:146:26
    |
 LL |     fn assoc_fn_test1(x: _);
@@ -474,7 +474,7 @@ help: use type parameters instead
 LL |     fn assoc_fn_test1<T>(x: T);
    |                      +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:148:26
    |
 LL |     fn assoc_fn_test2(x: _) -> _;
@@ -487,7 +487,7 @@ help: use type parameters instead
 LL |     fn assoc_fn_test2<T>(x: T) -> T;
    |                      +++    ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:150:28
    |
 LL |     fn assoc_fn_test3() -> _;
@@ -498,19 +498,19 @@ help: use type parameters instead
 LL |     fn assoc_fn_test3<T>() -> T;
    |                      +++      ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:190:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:192:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:194:14
    |
 LL |     const D: _ = 42;
@@ -519,13 +519,13 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:197:26
    |
 LL |     type F: std::ops::Fn(_);
    |                          ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:41:24
    |
 LL |     fn test9(&self) -> _ { () }
@@ -534,7 +534,7 @@ LL |     fn test9(&self) -> _ { () }
    |                        not allowed in type signatures
    |                        help: replace with the correct return type: `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:44:27
    |
 LL |     fn test10(&self, _x : _) { }
@@ -545,7 +545,7 @@ help: use type parameters instead
 LL |     fn test10<T>(&self, _x : T) { }
    |              +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:59:24
    |
 LL |     fn clone(&self) -> _ { Test9 }
@@ -554,7 +554,7 @@ LL |     fn clone(&self) -> _ { Test9 }
    |                        not allowed in type signatures
    |                        help: replace with the correct return type: `Test9`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:62:37
    |
 LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
@@ -565,7 +565,7 @@ help: use type parameters instead
 LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
    |                  +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:107:31
    |
 LL |         fn fn_test9(&self) -> _ { () }
@@ -574,7 +574,7 @@ LL |         fn fn_test9(&self) -> _ { () }
    |                               not allowed in type signatures
    |                               help: replace with the correct return type: `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:110:34
    |
 LL |         fn fn_test10(&self, _x : _) { }
@@ -585,7 +585,7 @@ help: use type parameters instead
 LL |         fn fn_test10<T>(&self, _x : T) { }
    |                     +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:115:28
    |
 LL |         fn clone(&self) -> _ { FnTest9 }
@@ -594,7 +594,7 @@ LL |         fn clone(&self) -> _ { FnTest9 }
    |                            not allowed in type signatures
    |                            help: replace with the correct return type: `FnTest9`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:118:41
    |
 LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
@@ -605,25 +605,25 @@ help: use type parameters instead
 LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
    |                      +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type A = _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:203:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:205:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:208:14
    |
 LL |     const D: _ = 42;
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.rs b/src/test/ui/typeck/typeck_type_placeholder_item_help.rs
index 3af5cf926ab..53f31b683c1 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item_help.rs
+++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.rs
@@ -2,27 +2,27 @@
 // using the `_` type placeholder.
 
 fn test1() -> _ { Some(42) }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
 const TEST2: _ = 42u32;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 
 const TEST3: _ = Some(42);
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 
 const TEST4: fn() -> _ = 42;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 trait Test5 {
     const TEST5: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 }
 
 struct Test6;
 
 impl Test6 {
     const TEST6: _ = 13;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 }
 
 pub fn main() {
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr
index 1b56b1033a8..e8191832318 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr
+++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item_help.rs:4:15
    |
 LL | fn test1() -> _ { Some(42) }
@@ -7,7 +7,7 @@ LL | fn test1() -> _ { Some(42) }
    |               not allowed in type signatures
    |               help: replace with the correct return type: `Option<i32>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:7:14
    |
 LL | const TEST2: _ = 42u32;
@@ -16,7 +16,7 @@ LL | const TEST2: _ = 42u32;
    |              not allowed in type signatures
    |              help: replace with the correct type: `u32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:10:14
    |
 LL | const TEST3: _ = Some(42);
@@ -25,13 +25,13 @@ LL | const TEST3: _ = Some(42);
    |              not allowed in type signatures
    |              help: replace with the correct type: `Option<i32>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item_help.rs:13:22
    |
 LL | const TEST4: fn() -> _ = 42;
    |                      ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:17:18
    |
 LL |     const TEST5: _ = 42;
@@ -40,7 +40,7 @@ LL |     const TEST5: _ = 42;
    |                  not allowed in type signatures
    |                  help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:24:18
    |
 LL |     const TEST6: _ = 13;
diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md
index b77c5a907c1..44c96f31d0b 100644
--- a/src/tools/build-manifest/README.md
+++ b/src/tools/build-manifest/README.md
@@ -20,8 +20,7 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to
 `path/to/output` with:
 
 ```
-$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \
-    CHANNEL VERSION
+$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com CHANNEL
 ```
 
 Remember to replace `CHANNEL` with the channel you produced dist artifacts of
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index c1579ae9ac5..6b56d6bc4ad 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -155,17 +155,19 @@ static TARGETS: &[&str] = &[
     "x86_64-unknown-hermit",
 ];
 
-static DOCS_TARGETS: &[&str] = &[
-    "aarch64-unknown-linux-gnu",
-    "i686-apple-darwin",
-    "i686-pc-windows-gnu",
-    "i686-pc-windows-msvc",
-    "i686-unknown-linux-gnu",
-    "x86_64-apple-darwin",
-    "x86_64-pc-windows-gnu",
-    "x86_64-pc-windows-msvc",
-    "x86_64-unknown-linux-gnu",
-    "x86_64-unknown-linux-musl",
+/// This allows the manifest to contain rust-docs for hosts that don't build
+/// docs.
+///
+/// Tuples of `(host_partial, host_instead)`. If the host does not have the
+/// rust-docs component available, then if the host name contains
+/// `host_partial`, it will use the docs from `host_instead` instead.
+///
+/// The order here matters, more specific entries should be first.
+static DOCS_FALLBACK: &[(&str, &str)] = &[
+    ("-apple-", "x86_64-apple-darwin"),
+    ("aarch64", "aarch64-unknown-linux-gnu"),
+    ("arm-", "aarch64-unknown-linux-gnu"),
+    ("", "x86_64-unknown-linux-gnu"),
 ];
 
 static MSI_INSTALLERS: &[&str] = &[
@@ -301,23 +303,27 @@ impl Builder {
     }
 
     fn add_packages_to(&mut self, manifest: &mut Manifest) {
-        let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets);
-        package("rustc", HOSTS);
-        package("rustc-dev", HOSTS);
-        package("reproducible-artifacts", HOSTS);
-        package("rustc-docs", HOSTS);
-        package("cargo", HOSTS);
-        package("rust-mingw", MINGW);
-        package("rust-std", TARGETS);
-        package("rust-docs", DOCS_TARGETS);
-        package("rust-src", &["*"]);
-        package("rls-preview", HOSTS);
-        package("rust-analyzer-preview", HOSTS);
-        package("clippy-preview", HOSTS);
-        package("miri-preview", HOSTS);
-        package("rustfmt-preview", HOSTS);
-        package("rust-analysis", TARGETS);
-        package("llvm-tools-preview", TARGETS);
+        macro_rules! package {
+            ($name:expr, $targets:expr) => {
+                self.package($name, &mut manifest.pkg, $targets, &[])
+            };
+        }
+        package!("rustc", HOSTS);
+        package!("rustc-dev", HOSTS);
+        package!("reproducible-artifacts", HOSTS);
+        package!("rustc-docs", HOSTS);
+        package!("cargo", HOSTS);
+        package!("rust-mingw", MINGW);
+        package!("rust-std", TARGETS);
+        self.package("rust-docs", &mut manifest.pkg, HOSTS, DOCS_FALLBACK);
+        package!("rust-src", &["*"]);
+        package!("rls-preview", HOSTS);
+        package!("rust-analyzer-preview", HOSTS);
+        package!("clippy-preview", HOSTS);
+        package!("miri-preview", HOSTS);
+        package!("rustfmt-preview", HOSTS);
+        package!("rust-analysis", TARGETS);
+        package!("llvm-tools-preview", TARGETS);
     }
 
     fn add_artifacts_to(&mut self, manifest: &mut Manifest) {
@@ -500,7 +506,13 @@ impl Builder {
             .extend(pkgs.iter().map(|s| (*s).to_owned()));
     }
 
-    fn package(&mut self, pkgname: &str, dst: &mut BTreeMap<String, Package>, targets: &[&str]) {
+    fn package(
+        &mut self,
+        pkgname: &str,
+        dst: &mut BTreeMap<String, Package>,
+        targets: &[&str],
+        fallback: &[(&str, &str)],
+    ) {
         let version_info = self
             .versions
             .version(&PkgType::from_component(pkgname))
@@ -512,16 +524,32 @@ impl Builder {
             is_present = false; // Pretend the component is entirely missing.
         }
 
+        macro_rules! tarball_name {
+            ($target_name:expr) => {
+                self.versions.tarball_name(&PkgType::from_component(pkgname), $target_name).unwrap()
+            };
+        }
+        let mut target_from_compressed_tar = |target_name| {
+            let target = Target::from_compressed_tar(self, &tarball_name!(target_name));
+            if target.available {
+                return target;
+            }
+            for (substr, fallback_target) in fallback {
+                if target_name.contains(substr) {
+                    let t = Target::from_compressed_tar(self, &tarball_name!(fallback_target));
+                    // Fallbacks must always be available.
+                    assert!(t.available);
+                    return t;
+                }
+            }
+            Target::unavailable()
+        };
+
         let targets = targets
             .iter()
             .map(|name| {
                 let target = if is_present {
-                    let filename = self
-                        .versions
-                        .tarball_name(&PkgType::from_component(pkgname), name)
-                        .unwrap();
-
-                    Target::from_compressed_tar(self, &filename)
+                    target_from_compressed_tar(name)
                 } else {
                     // If the component is not present for this build add it anyway but mark it as
                     // unavailable -- this way rustup won't allow upgrades without --force
diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs
index 11575139adc..95c2297de26 100644
--- a/src/tools/build-manifest/src/versions.rs
+++ b/src/tools/build-manifest/src/versions.rs
@@ -169,7 +169,7 @@ impl Versions {
     }
 
     pub(crate) fn archive_name(
-        &mut self,
+        &self,
         package: &PkgType,
         target: &str,
         extension: &str,
@@ -189,11 +189,7 @@ impl Versions {
         }
     }
 
-    pub(crate) fn tarball_name(
-        &mut self,
-        package: &PkgType,
-        target: &str,
-    ) -> Result<String, Error> {
+    pub(crate) fn tarball_name(&self, package: &PkgType, target: &str) -> Result<String, Error> {
         self.archive_name(package, target, "tar.gz")
     }
 
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 06b9d31743210b788b130c8a484c2838afa6fc2
+Subproject 95bb3c92bf516017e812e7f1c14c2dea3845b30
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 8f4da9a3827..258a8256f53 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -3049,6 +3049,7 @@ Released 2018-09-13
 [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
+[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
diff --git a/src/tools/clippy/COPYRIGHT b/src/tools/clippy/COPYRIGHT
index 238c919b69d..a6be75b5e31 100644
--- a/src/tools/clippy/COPYRIGHT
+++ b/src/tools/clippy/COPYRIGHT
@@ -1,4 +1,4 @@
-Copyright 2014-2021 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
diff --git a/src/tools/clippy/LICENSE-APACHE b/src/tools/clippy/LICENSE-APACHE
index 04169a42b8b..0d62c37278e 100644
--- a/src/tools/clippy/LICENSE-APACHE
+++ b/src/tools/clippy/LICENSE-APACHE
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
    same "printed page" as the copyright notice for easier
    identification within third-party archives.
 
-Copyright 2014-2021 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/src/tools/clippy/LICENSE-MIT b/src/tools/clippy/LICENSE-MIT
index 90a2d3950d1..b724b24aa83 100644
--- a/src/tools/clippy/LICENSE-MIT
+++ b/src/tools/clippy/LICENSE-MIT
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2014-2021 The Rust Project Developers
+Copyright (c) 2014-2022 The Rust Project Developers
 
 Permission is hereby granted, free of charge, to any
 person obtaining a copy of this software and associated
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index f001a42d917..edbc626e354 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -238,7 +238,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
 
 ## License
 
-Copyright 2014-2021 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs
index 0977cf22b2c..ca4af66cad1 100644
--- a/src/tools/clippy/clippy_lints/src/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs
@@ -18,14 +18,14 @@ declare_clippy_lint! {
     /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
     /// table:
     ///
-    /// |Comparison  |Bit Op|Example     |is always|Formula               |
-    /// |------------|------|------------|---------|----------------------|
-    /// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
-    /// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
-    /// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
-    /// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
-    /// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
-    /// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
+    /// |Comparison  |Bit Op|Example      |is always|Formula               |
+    /// |------------|------|-------------|---------|----------------------|
+    /// |`==` or `!=`| `&`  |`x & 2 == 3` |`false`  |`c & m != c`          |
+    /// |`<`  or `>=`| `&`  |`x & 2 < 3`  |`true`   |`m < c`               |
+    /// |`>`  or `<=`| `&`  |`x & 1 > 1`  |`false`  |`m <= c`              |
+    /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false`  |`c \| m != c`         |
+    /// |`<`  or `>=`| `\|` |`x \| 1 < 1` |`false`  |`m >= c`              |
+    /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true`   |`m > c`               |
     ///
     /// ### Why is this bad?
     /// If the bits that the comparison cares about are always
@@ -53,10 +53,10 @@ declare_clippy_lint! {
     /// without changing the outcome. The basic structure can be seen in the
     /// following table:
     ///
-    /// |Comparison| Bit Op  |Example    |equals |
-    /// |----------|---------|-----------|-------|
-    /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
-    /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
+    /// |Comparison| Bit Op   |Example     |equals |
+    /// |----------|----------|------------|-------|
+    /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
+    /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
     ///
     /// ### Why is this bad?
     /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 39456e25ff4..8b79f1600ae 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
                 lint_same_cond(cx, &conds);
                 lint_same_fns_in_if_cond(cx, &conds);
                 // Block duplication
-                lint_same_then_else(cx, &blocks, conds.len() == blocks.len(), expr);
+                lint_same_then_else(cx, &conds, &blocks, conds.len() == blocks.len(), expr);
             }
         }
     }
@@ -192,6 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
 /// Implementation of `BRANCHES_SHARING_CODE` and `IF_SAME_THEN_ELSE` if the blocks are equal.
 fn lint_same_then_else<'tcx>(
     cx: &LateContext<'tcx>,
+    conds: &[&'tcx Expr<'_>],
     blocks: &[&Block<'tcx>],
     has_conditional_else: bool,
     expr: &'tcx Expr<'_>,
@@ -204,7 +205,7 @@ fn lint_same_then_else<'tcx>(
     // Check if each block has shared code
     let has_expr = blocks[0].expr.is_some();
 
-    let (start_eq, mut end_eq, expr_eq) = if let Some(block_eq) = scan_block_for_eq(cx, blocks) {
+    let (start_eq, mut end_eq, expr_eq) = if let Some(block_eq) = scan_block_for_eq(cx, conds, blocks) {
         (block_eq.start_eq, block_eq.end_eq, block_eq.expr_eq)
     } else {
         return;
@@ -316,14 +317,14 @@ struct BlockEqual {
 
 /// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
 /// abort any further processing and avoid duplicate lint triggers.
-fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<BlockEqual> {
+fn scan_block_for_eq(cx: &LateContext<'_>, conds: &[&Expr<'_>], blocks: &[&Block<'_>]) -> Option<BlockEqual> {
     let mut start_eq = usize::MAX;
     let mut end_eq = usize::MAX;
     let mut expr_eq = true;
-    let mut iter = blocks.windows(2);
-    while let Some(&[win0, win1]) = iter.next() {
-        let l_stmts = win0.stmts;
-        let r_stmts = win1.stmts;
+    let mut iter = blocks.windows(2).enumerate();
+    while let Some((i, &[block0, block1])) = iter.next() {
+        let l_stmts = block0.stmts;
+        let r_stmts = block1.stmts;
 
         // `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
         // The comparison therefore needs to be done in a way that builds the correct context.
@@ -340,22 +341,26 @@ fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<Bloc
             it1.zip(it2)
                 .fold(0, |acc, (l, r)| if evaluator.eq_stmt(l, r) { acc + 1 } else { 0 })
         };
-        let block_expr_eq = both(&win0.expr, &win1.expr, |l, r| evaluator.eq_expr(l, r));
+        let block_expr_eq = both(&block0.expr, &block1.expr, |l, r| evaluator.eq_expr(l, r));
 
         // IF_SAME_THEN_ELSE
         if_chain! {
             if block_expr_eq;
             if l_stmts.len() == r_stmts.len();
             if l_stmts.len() == current_start_eq;
-            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win0.hir_id);
-            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win1.hir_id);
+            // `conds` may have one last item than `blocks`.
+            // Any `i` from `blocks.windows(2)` will exist in `conds`, but `i+1` may not exist on the last iteration.
+            if !matches!(conds[i].kind, ExprKind::Let(..));
+            if !matches!(conds.get(i + 1).map(|e| &e.kind), Some(ExprKind::Let(..)));
+            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, block0.hir_id);
+            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, block1.hir_id);
             then {
                 span_lint_and_note(
                     cx,
                     IF_SAME_THEN_ELSE,
-                    win0.span,
+                    block0.span,
                     "this `if` has identical blocks",
-                    Some(win1.span),
+                    Some(block1.span),
                     "same as this",
                 );
 
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 688d8f8630f..395c920c997 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::kw;
-use rustc_span::{sym, Span};
+use rustc_span::{sym, BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -84,7 +84,22 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
                         ExprKind::MethodCall(path, ..) => path.ident.name.as_str() == "to_string",
                         _ => false,
                     };
-                    let sugg = if is_new_string {
+                    let sugg = if format_args.format_string_span.contains(value.span) {
+                        // Implicit argument. e.g. `format!("{x}")` span points to `{x}`
+                        let spdata = value.span.data();
+                        let span = Span::new(
+                            spdata.lo + BytePos(1),
+                            spdata.hi - BytePos(1),
+                            spdata.ctxt,
+                            spdata.parent
+                        );
+                        let snip = snippet_with_applicability(cx, span, "..", &mut applicability);
+                        if is_new_string {
+                            snip.into()
+                        } else {
+                            format!("{snip}.to_string()")
+                        }
+                    } else if is_new_string {
                         snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned()
                     } else {
                         let sugg = Sugg::hir_with_applicability(cx, value, "<arg>", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 8902ee14572..ab3dae4b67f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -42,8 +42,7 @@ fn check_raw_ptr<'tcx>(
     let expr = &body.value;
     if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
         let raw_ptrs = iter_input_pats(decl, body)
-            .zip(decl.inputs.iter())
-            .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
+            .filter_map(|arg| raw_ptr_arg(cx, arg))
             .collect::<HirIdSet>();
 
         if !raw_ptrs.is_empty() {
@@ -59,8 +58,12 @@ fn check_raw_ptr<'tcx>(
     }
 }
 
-fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option<hir::HirId> {
-    if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
+fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<hir::HirId> {
+    if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_))) = (
+        &arg.pat.kind,
+        cx.maybe_typeck_results()
+            .map(|typeck_results| typeck_results.pat_ty(arg.pat).kind()),
+    ) {
         Some(id)
     } else {
         None
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index d3bdc819a9f..b56d87c5348 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
 
 fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
     if sig.decl.implicit_self.has_implicit_self() {
-        let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output();
+        let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).output());
         let ret_ty = cx
             .tcx
             .try_normalize_erasing_regions(cx.param_env, ret_ty)
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index 26fb4259952..87fd7f99748 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -156,6 +156,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::ITER_NEXT_SLICE),
     LintId::of(methods::ITER_NTH),
     LintId::of(methods::ITER_NTH_ZERO),
+    LintId::of(methods::ITER_OVEREAGER_CLONED),
     LintId::of(methods::ITER_SKIP_NEXT),
     LintId::of(methods::MANUAL_FILTER_MAP),
     LintId::of(methods::MANUAL_FIND_MAP),
@@ -249,7 +250,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(reference::REF_IN_DEREF),
     LintId::of(regex::INVALID_REGEX),
     LintId::of(repeat_once::REPEAT_ONCE),
-    LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(returns::LET_AND_RETURN),
     LintId::of(returns::NEEDLESS_RETURN),
     LintId::of(self_assignment::SELF_ASSIGNMENT),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index 746bdb19c3d..56146a0fd3a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -288,6 +288,7 @@ store.register_lints(&[
     methods::ITER_NEXT_SLICE,
     methods::ITER_NTH,
     methods::ITER_NTH_ZERO,
+    methods::ITER_OVEREAGER_CLONED,
     methods::ITER_SKIP_NEXT,
     methods::MANUAL_FILTER_MAP,
     methods::MANUAL_FIND_MAP,
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
index 1744b7c8250..1292675f4a9 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
@@ -81,6 +81,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(ranges::RANGE_PLUS_ONE),
     LintId::of(redundant_else::REDUNDANT_ELSE),
     LintId::of(ref_option_ref::REF_OPTION_REF),
+    LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
     LintId::of(strings::STRING_ADD_ASSIGN),
     LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
index f9ffd4cf829..c44ef124bfa 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
@@ -14,6 +14,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
     LintId::of(methods::EXPECT_FUN_CALL),
     LintId::of(methods::EXTEND_WITH_DRAIN),
     LintId::of(methods::ITER_NTH),
+    LintId::of(methods::ITER_OVEREAGER_CLONED),
     LintId::of(methods::MANUAL_STR_REPEAT),
     LintId::of(methods::OR_FUN_CALL),
     LintId::of(methods::SINGLE_CHAR_PATTERN),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
index 8594338ffa5..10f8ae4b7f7 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
@@ -16,7 +16,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
-    LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 ])
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 86819752f90..2af3555e370 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -6,7 +6,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
+    Term, AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
     IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -140,7 +140,7 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
         if args.bindings.len() == 1;
         let binding = &args.bindings[0];
         if binding.ident.name == sym::Output;
-        if let TypeBindingKind::Equality{ty: output} = binding.kind;
+        if let TypeBindingKind::Equality{term: Term::Ty(output)} = binding.kind;
         then {
             return Some(output)
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 90492ffda3c..865e7702b71 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,31 +1,40 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::peel_mid_ty_refs;
 use clippy_utils::{is_diag_item_method, is_diag_trait_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty::TyS;
-use rustc_span::{sym, Span};
+use rustc_span::sym;
 
 use super::IMPLICIT_CLONE;
 
-pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) {
+pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if is_clone_like(cx, method_name, method_def_id);
         let return_type = cx.typeck_results().expr_ty(expr);
-        let input_type = cx.typeck_results().expr_ty(recv).peel_refs();
+        let input_type = cx.typeck_results().expr_ty(recv);
+        let (input_type, ref_count) = peel_mid_ty_refs(input_type);
         if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did));
         if TyS::same_type(return_type, input_type);
         then {
+            let mut app = Applicability::MachineApplicable;
+            let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
             span_lint_and_sugg(
                 cx,
                 IMPLICIT_CLONE,
-                span,
+                expr.span,
                 &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name),
                 "consider using",
-                "clone".to_string(),
-                Applicability::MachineApplicable
+                if ref_count > 1 {
+                    format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip)
+                } else {
+                    format!("{}.clone()", recv_snip)
+                },
+                app,
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
new file mode 100644
index 00000000000..ca33bfc643d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -0,0 +1,62 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::{get_iterator_item_ty, is_copy};
+use itertools::Itertools;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use std::ops::Not;
+
+use super::ITER_OVEREAGER_CLONED;
+use crate::redundant_clone::REDUNDANT_CLONE;
+
+/// lint overeager use of `cloned()` for `Iterator`s
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    name: &str,
+    map_arg: &[hir::Expr<'_>],
+) {
+    // Check if it's iterator and get type associated with `Item`.
+    let inner_ty = match get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)) {
+        Some(ty) => ty,
+        _ => return,
+    };
+
+    match inner_ty.kind() {
+        ty::Ref(_, ty, _) if !is_copy(cx, ty) => {},
+        _ => return,
+    };
+
+    let (lint, preserve_cloned) = match name {
+        "count" => (REDUNDANT_CLONE, false),
+        _ => (ITER_OVEREAGER_CLONED, true),
+    };
+    let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default();
+    let msg = format!(
+        "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead",
+        name,
+        wildcard_params,
+        name,
+        wildcard_params,
+        preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
+    );
+
+    span_lint_and_sugg(
+        cx,
+        lint,
+        expr.span,
+        &msg,
+        "try this",
+        format!(
+            "{}.{}({}){}",
+            snippet(cx, recv.span, ".."),
+            name,
+            map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "),
+            preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
+        ),
+        Applicability::MachineApplicable,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index ed5136e7d00..a9a06c3db75 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -30,6 +30,7 @@ mod iter_count;
 mod iter_next_slice;
 mod iter_nth;
 mod iter_nth_zero;
+mod iter_overeager_cloned;
 mod iter_skip_next;
 mod iterator_step_by_zero;
 mod manual_saturating_arithmetic;
@@ -108,6 +109,41 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
+    ///
+    /// ### Why is this bad?
+    /// It's often inefficient to clone all elements of an iterator, when eventually, only some
+    /// of them will be consumed.
+    ///
+    /// ### Examples
+    /// ```rust
+    /// # let vec = vec!["string".to_string()];
+    ///
+    /// // Bad
+    /// vec.iter().cloned().take(10);
+    ///
+    /// // Good
+    /// vec.iter().take(10).cloned();
+    ///
+    /// // Bad
+    /// vec.iter().cloned().last();
+    ///
+    /// // Good
+    /// vec.iter().last().cloned();
+    ///
+    /// ```
+    /// ### Known Problems
+    /// This `lint` removes the side of effect of cloning items in the iterator.
+    /// A code that relies on that side-effect could fail.
+    ///
+    #[clippy::version = "1.59.0"]
+    pub ITER_OVEREAGER_CLONED,
+    perf,
+    "using `cloned()` early with `Iterator::iter()` can lead to some performance inefficiencies"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
     /// used instead.
     ///
@@ -1950,6 +1986,7 @@ impl_lint_pass!(Methods => [
     CLONE_ON_COPY,
     CLONE_ON_REF_PTR,
     CLONE_DOUBLE_REF,
+    ITER_OVEREAGER_CLONED,
     CLONED_INSTEAD_OF_COPIED,
     FLAT_MAP_OPTION,
     INEFFICIENT_TO_STRING,
@@ -2141,12 +2178,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+                        let assoc_ty = match projection_predicate.term {
+                          ty::Term::Ty(ty) => ty,
+                          ty::Term::Const(_c) => continue,
+                        };
                         // walk the associated type and check for Self
                         if let Some(self_adt) = self_ty.ty_adt_def() {
-                            if contains_adt_constructor(projection_predicate.ty, self_adt) {
+                            if contains_adt_constructor(assoc_ty, self_adt) {
                                 return;
                             }
-                        } else if contains_ty(projection_predicate.ty, self_ty) {
+                        } else if contains_ty(assoc_ty, self_ty) {
                             return;
                         }
                     }
@@ -2243,9 +2284,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 },
                 _ => {},
             },
-            ("count", []) => match method_call(recv) {
-                Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
-                    iter_count::check(cx, expr, recv2, name);
+            (name @ "count", args @ []) => match method_call(recv) {
+                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+                    iter_count::check(cx, expr, recv2, name2);
                 },
                 Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
                 _ => {},
@@ -2266,10 +2308,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 flat_map_identity::check(cx, expr, arg, span);
                 flat_map_option::check(cx, expr, arg, span);
             },
-            ("flatten", []) => {
-                if let Some(("map", [recv, map_arg], _)) = method_call(recv) {
-                    map_flatten::check(cx, expr, recv, map_arg);
-                }
+            (name @ "flatten", args @ []) => match method_call(recv) {
+                Some(("map", [recv, map_arg], _)) => map_flatten::check(cx, expr, recv, map_arg),
+                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                _ => {},
             },
             ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
             ("for_each", [_]) => {
@@ -2281,6 +2323,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("is_file", []) => filetype_is_file::check(cx, expr, recv),
             ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
             ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+            ("last", args @ []) | ("skip", args @ [_]) => {
+                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let ("cloned", []) = (name2, args2) {
+                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
+                    }
+                }
+            },
             ("map", [m_arg]) => {
                 if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
                     match (name, args) {
@@ -2296,20 +2345,22 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 map_identity::check(cx, expr, recv, m_arg, span);
             },
             ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
-            ("next", []) => {
-                if let Some((name, [recv, args @ ..], _)) = method_call(recv) {
-                    match (name, args) {
-                        ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
-                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
-                        ("iter", []) => iter_next_slice::check(cx, expr, recv),
-                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg),
+            (name @ "next", args @ []) => {
+                if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
+                    match (name2, args2) {
+                        ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                        ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
+                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, msrv),
+                        ("iter", []) => iter_next_slice::check(cx, expr, recv2),
+                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
                         ("skip_while", [_]) => skip_while_next::check(cx, expr),
                         _ => {},
                     }
                 }
             },
-            ("nth", [n_arg]) => match method_call(recv) {
+            ("nth", args @ [n_arg]) => match method_call(recv) {
                 Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
                 Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
                 Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
                 _ => iter_nth_zero::check(cx, expr, recv, n_arg),
@@ -2337,8 +2388,15 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 }
             },
             ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
+            ("take", args @ [_arg]) => {
+                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let ("cloned", []) = (name2, args2) {
+                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
+                    }
+                }
+            },
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
-                implicit_clone::check(cx, name, expr, recv, span);
+                implicit_clone::check(cx, name, expr, recv);
             },
             ("unwrap", []) => match method_call(recv) {
                 Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false),
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 4e4653dadca..448dc4e6147 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -4,6 +4,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_mac
 use clippy_utils::ty::{implements_trait, match_type};
 use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths};
 use if_chain::if_chain;
+use rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -23,6 +24,7 @@ pub(super) fn check<'tcx>(
     args: &'tcx [hir::Expr<'_>],
 ) {
     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
+    #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
         name: &str,
@@ -31,6 +33,7 @@ pub(super) fn check<'tcx>(
         arg: &hir::Expr<'_>,
         or_has_args: bool,
         span: Span,
+        method_span: Span,
     ) -> bool {
         let is_default_default = || is_trait_item(cx, fun, sym::Default);
 
@@ -52,16 +55,27 @@ pub(super) fn check<'tcx>(
 
             then {
                 let mut applicability = Applicability::MachineApplicable;
+                let hint = "unwrap_or_default()";
+                let mut sugg_span = span;
+
+                let mut sugg: String = format!(
+                    "{}.{}",
+                    snippet_with_applicability(cx, self_expr.span, "..", &mut applicability),
+                    hint
+                );
+
+                if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES {
+                    sugg_span = method_span.with_hi(span.hi());
+                    sugg = hint.to_string();
+                }
+
                 span_lint_and_sugg(
                     cx,
                     OR_FUN_CALL,
-                    span,
+                    sugg_span,
                     &format!("use of `{}` followed by a call to `{}`", name, path),
                     "try this",
-                    format!(
-                        "{}.unwrap_or_default()",
-                        snippet_with_applicability(cx, self_expr.span, "..", &mut applicability)
-                    ),
+                    sugg,
                     applicability,
                 );
 
@@ -164,7 +178,7 @@ pub(super) fn check<'tcx>(
         match inner_arg.kind {
             hir::ExprKind::Call(fun, or_args) => {
                 let or_has_args = !or_args.is_empty();
-                if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) {
+                if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span, method_span) {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
                     check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index e5b6d296b2d..9162de3ccea 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -243,9 +243,10 @@ fn check_other_call_arg<'tcx>(
         if if trait_predicate.def_id() == deref_trait_id {
             if let [projection_predicate] = projection_predicates[..] {
                 let normalized_ty =
-                    cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty);
+                    cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
                 implements_trait(cx, receiver_ty, deref_trait_id, &[])
-                    && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
+                    && get_associated_type(cx, receiver_ty, deref_trait_id,
+                    "Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
             } else {
                 false
             }
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 21b3f81d5d9..8db71d1e967 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -548,6 +548,7 @@ fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
 }
 
+#[allow(clippy::too_many_lines)]
 fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
     #[derive(Default)]
     struct EqImpl {
@@ -644,10 +645,26 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
                 hint = expr_snip;
             } else {
                 span = expr.span.to(other.span);
+
+                let cmp_span = if other.span < expr.span {
+                    other.span.between(expr.span)
+                } else {
+                    expr.span.between(other.span)
+                };
                 if eq_impl.ty_eq_other {
-                    hint = format!("{} == {}", expr_snip, snippet(cx, other.span, ".."));
+                    hint = format!(
+                        "{}{}{}",
+                        expr_snip,
+                        snippet(cx, cmp_span, ".."),
+                        snippet(cx, other.span, "..")
+                    );
                 } else {
-                    hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip);
+                    hint = format!(
+                        "{}{}{}",
+                        snippet(cx, other.span, ".."),
+                        snippet(cx, cmp_span, ".."),
+                        expr_snip
+                    );
                 }
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 5dafd08cf3b..79f104eac0b 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -60,7 +60,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.59.0"]
     pub RETURN_SELF_NOT_MUST_USE,
-    suspicious,
+    pedantic,
     "missing `#[must_use]` annotation on a method returning `Self`"
 }
 
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 fe35ff33d35..68156df2ece 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
@@ -98,9 +98,10 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
                         if trait_pred.self_ty() == inp;
                         if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
                         then {
-                            if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.ty) {
+                            if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
+                            return_ty_pred.term.ty()) {
                                 args_to_check.push((i, "Ord".to_string()));
-                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) {
+                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
                                 args_to_check.push((i, "PartialOrd".to_string()));
                             }
                         }
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 3d3180521ab..604c95d2bc8 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -645,11 +645,19 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
     }
 }
 
-pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool {
-    use AssocTyConstraintKind::*;
+fn eq_term(l: &Term, r: &Term) -> bool {
+  match (l, r) {
+    (Term::Ty(l), Term::Ty(r)) => eq_ty(l,r),
+    (Term::Const(l), Term::Const(r)) => eq_anon_const(l,r),
+    _ => false,
+  }
+}
+
+pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
+    use AssocConstraintKind::*;
     eq_id(l.ident, r.ident)
         && match (&l.kind, &r.kind) {
-            (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
+            (Equality { term: l }, Equality { term: r }) => eq_term(l, r),
             (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound),
             _ => false,
         }
diff --git a/src/tools/clippy/rustc_tools_util/README.md b/src/tools/clippy/rustc_tools_util/README.md
index 6027538dc4a..01891b51d3b 100644
--- a/src/tools/clippy/rustc_tools_util/README.md
+++ b/src/tools/clippy/rustc_tools_util/README.md
@@ -53,7 +53,7 @@ This gives the following output in clippy:
 
 ## License
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed
new file mode 100644
index 00000000000..44e41bdd114
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed
@@ -0,0 +1,29 @@
+// run-rustfix
+
+use std::fmt::{self, Display};
+
+fn main() {
+    let a = Foo;
+
+    if a != "bar" {
+        println!("foo");
+    }
+
+    if a != "bar" {
+        println!("foo");
+    }
+}
+
+struct Foo;
+
+impl Display for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "foo")
+    }
+}
+
+impl PartialEq<&str> for Foo {
+    fn eq(&self, other: &&str) -> bool {
+        "foo" == *other
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs
new file mode 100644
index 00000000000..662673abb62
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs
@@ -0,0 +1,29 @@
+// run-rustfix
+
+use std::fmt::{self, Display};
+
+fn main() {
+    let a = Foo;
+
+    if a.to_string() != "bar" {
+        println!("foo");
+    }
+
+    if "bar" != a.to_string() {
+        println!("foo");
+    }
+}
+
+struct Foo;
+
+impl Display for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "foo")
+    }
+}
+
+impl PartialEq<&str> for Foo {
+    fn eq(&self, other: &&str) -> bool {
+        "foo" == *other
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr
new file mode 100644
index 00000000000..e4d0d822bb1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr
@@ -0,0 +1,18 @@
+error: this creates an owned instance just for comparison
+  --> $DIR/comparison_flip.rs:8:8
+   |
+LL |     if a.to_string() != "bar" {
+   |        ^^^^^^^^^^^^^ help: try: `a`
+   |
+   = note: `-D clippy::cmp-owned` implied by `-D warnings`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/comparison_flip.rs:12:17
+   |
+LL |     if "bar" != a.to_string() {
+   |        ---------^^^^^^^^^^^^^
+   |        |
+   |        help: try: `a != "bar"`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed
index 64cb7b1cfb8..78d2bfd474e 100644
--- a/src/tools/clippy/tests/ui/format.fixed
+++ b/src/tools/clippy/tests/ui/format.fixed
@@ -73,4 +73,10 @@ fn main() {
     let _s: String = (&*v.join("\n")).to_string();
 
     format!("prepend {:+}", "s");
+
+    // Issue #8290
+    let x = "foo";
+    let _ = x.to_string();
+    let _ = format!("{x:?}"); // Don't lint on debug
+    let _ = x.to_string();
 }
diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs
index a065b1b5683..009c1aa216f 100644
--- a/src/tools/clippy/tests/ui/format.rs
+++ b/src/tools/clippy/tests/ui/format.rs
@@ -75,4 +75,10 @@ fn main() {
     let _s: String = format!("{}", &*v.join("\n"));
 
     format!("prepend {:+}", "s");
+
+    // Issue #8290
+    let x = "foo";
+    let _ = format!("{x}");
+    let _ = format!("{x:?}"); // Don't lint on debug
+    let _ = format!("{y}", y = x);
 }
diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr
index 58ad7499bb2..660be57585e 100644
--- a/src/tools/clippy/tests/ui/format.stderr
+++ b/src/tools/clippy/tests/ui/format.stderr
@@ -99,5 +99,17 @@ error: useless use of `format!`
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
-error: aborting due to 15 previous errors
+error: useless use of `format!`
+  --> $DIR/format.rs:81:13
+   |
+LL |     let _ = format!("{x}");
+   |             ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:83:13
+   |
+LL |     let _ = format!("{y}", y = x);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/functions.rs b/src/tools/clippy/tests/ui/functions.rs
index 271754cb06e..5521870eaec 100644
--- a/src/tools/clippy/tests/ui/functions.rs
+++ b/src/tools/clippy/tests/ui/functions.rs
@@ -78,6 +78,14 @@ pub fn public(p: *const u8) {
     unsafe { std::ptr::read(p) };
 }
 
+type Alias = *const u8;
+
+pub fn type_alias(p: Alias) {
+    println!("{}", unsafe { *p });
+    println!("{:?}", unsafe { p.as_ref() });
+    unsafe { std::ptr::read(p) };
+}
+
 impl Bar {
     fn private(self, p: *const u8) {
         println!("{}", unsafe { *p });
diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr
index a2b8c2a384b..8ebd4997f4f 100644
--- a/src/tools/clippy/tests/ui/functions.stderr
+++ b/src/tools/clippy/tests/ui/functions.stderr
@@ -69,22 +69,40 @@ LL |     unsafe { std::ptr::read(p) };
    |                             ^
 
 error: this public function might dereference a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:87:34
+  --> $DIR/functions.rs:84:30
+   |
+LL |     println!("{}", unsafe { *p });
+   |                              ^
+
+error: this public function might dereference a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:85:31
+   |
+LL |     println!("{:?}", unsafe { p.as_ref() });
+   |                               ^
+
+error: this public function might dereference a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:86:29
+   |
+LL |     unsafe { std::ptr::read(p) };
+   |                             ^
+
+error: this public function might dereference a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:95:34
    |
 LL |         println!("{}", unsafe { *p });
    |                                  ^
 
 error: this public function might dereference a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:88:35
+  --> $DIR/functions.rs:96:35
    |
 LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
 error: this public function might dereference a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:89:33
+  --> $DIR/functions.rs:97:33
    |
 LL |         unsafe { std::ptr::read(p) };
    |                                 ^
 
-error: aborting due to 13 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs
index 69189d9e0c0..0016009a02f 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs
@@ -138,6 +138,23 @@ fn if_same_then_else2() -> Result<&'static str, ()> {
         let (y, x) = (1, 2);
         return Ok(&foo[x..y]);
     }
+
+    // Issue #7579
+    let _ = if let Some(0) = None { 0 } else { 0 };
+
+    if true {
+        return Err(());
+    } else if let Some(0) = None {
+        return Err(());
+    }
+
+    let _ = if let Some(0) = None {
+        0
+    } else if let Some(1) = None {
+        0
+    } else {
+        0
+    };
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/implicit_clone.rs b/src/tools/clippy/tests/ui/implicit_clone.rs
index cef71cf79d7..639fecb8927 100644
--- a/src/tools/clippy/tests/ui/implicit_clone.rs
+++ b/src/tools/clippy/tests/ui/implicit_clone.rs
@@ -105,4 +105,13 @@ fn main() {
     let os_str = OsStr::new("foo");
     let _ = os_str.to_owned();
     let _ = os_str.to_os_string();
+
+    // issue #8227
+    let pathbuf_ref = &pathbuf;
+    let pathbuf_ref = &pathbuf_ref;
+    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf`
+    let _ = pathbuf_ref.to_path_buf();
+    let pathbuf_ref = &pathbuf_ref;
+    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
+    let _ = pathbuf_ref.to_path_buf();
 }
diff --git a/src/tools/clippy/tests/ui/implicit_clone.stderr b/src/tools/clippy/tests/ui/implicit_clone.stderr
index e6f7527b672..0f412424190 100644
--- a/src/tools/clippy/tests/ui/implicit_clone.stderr
+++ b/src/tools/clippy/tests/ui/implicit_clone.stderr
@@ -1,64 +1,76 @@
 error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:65:17
+  --> $DIR/implicit_clone.rs:65:13
    |
 LL |     let _ = vec.to_owned();
-   |                 ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^ help: consider using: `vec.clone()`
    |
    = note: `-D clippy::implicit-clone` implied by `-D warnings`
 
 error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type
-  --> $DIR/implicit_clone.rs:66:17
+  --> $DIR/implicit_clone.rs:66:13
    |
 LL |     let _ = vec.to_vec();
-   |                 ^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^ help: consider using: `vec.clone()`
 
 error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:70:21
+  --> $DIR/implicit_clone.rs:70:13
    |
 LL |     let _ = vec_ref.to_owned();
-   |                     ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()`
 
 error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type
-  --> $DIR/implicit_clone.rs:71:21
+  --> $DIR/implicit_clone.rs:71:13
    |
 LL |     let _ = vec_ref.to_vec();
-   |                     ^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()`
 
 error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:83:17
+  --> $DIR/implicit_clone.rs:83:13
    |
 LL |     let _ = str.to_owned();
-   |                 ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^ help: consider using: `str.clone()`
 
 error: implicitly cloning a `Kitten` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:87:20
+  --> $DIR/implicit_clone.rs:87:13
    |
 LL |     let _ = kitten.to_owned();
-   |                    ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `kitten.clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:97:21
+  --> $DIR/implicit_clone.rs:97:13
    |
 LL |     let _ = pathbuf.to_owned();
-   |                     ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
-  --> $DIR/implicit_clone.rs:98:21
+  --> $DIR/implicit_clone.rs:98:13
    |
 LL |     let _ = pathbuf.to_path_buf();
-   |                     ^^^^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()`
 
 error: implicitly cloning a `OsString` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:101:23
+  --> $DIR/implicit_clone.rs:101:13
    |
 LL |     let _ = os_string.to_owned();
-   |                       ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()`
 
 error: implicitly cloning a `OsString` by calling `to_os_string` on its dereferenced type
-  --> $DIR/implicit_clone.rs:102:23
+  --> $DIR/implicit_clone.rs:102:13
    |
 LL |     let _ = os_string.to_os_string();
-   |                       ^^^^^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()`
 
-error: aborting due to 10 previous errors
+error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
+  --> $DIR/implicit_clone.rs:113:13
+   |
+LL |     let _ = pathbuf_ref.to_path_buf();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(*pathbuf_ref).clone()`
+
+error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
+  --> $DIR/implicit_clone.rs:116:13
+   |
+LL |     let _ = pathbuf_ref.to_path_buf();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs
index 2c91e02e842..cce216fc649 100644
--- a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs
@@ -64,4 +64,11 @@ impl S {
     }
 }
 
+struct S2([u8]);
+impl S2 {
+    fn iter(&self) -> core::slice::Iter<u8> {
+        self.0.iter()
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
new file mode 100644
index 00000000000..a9041671101
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+
+fn main() {
+    let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
+
+    let _: Option<String> = vec.iter().last().cloned();
+
+    let _: Option<String> = vec.iter().chain(vec.iter()).next().cloned();
+
+    let _: usize = vec.iter().filter(|x| x == &"2").count();
+
+    let _: Vec<_> = vec.iter().take(2).cloned().collect();
+
+    let _: Vec<_> = vec.iter().skip(2).cloned().collect();
+
+    let _ = vec.iter().filter(|x| x == &"2").nth(2).cloned();
+
+    let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+        .iter().flatten().cloned();
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().map(|x| x.len());
+
+    // This would fail if changed.
+    let _ = vec.iter().cloned().map(|x| x + "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().find(|x| x == "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().all(|x| x.len() == 1);
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().any(|x| x.len() == 1);
+
+    // Should probably stay as it is.
+    let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
+}
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
new file mode 100644
index 00000000000..dd04e33a4b3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
@@ -0,0 +1,47 @@
+// run-rustfix
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+
+fn main() {
+    let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
+
+    let _: Option<String> = vec.iter().cloned().last();
+
+    let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
+
+    let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
+
+    let _: Vec<_> = vec.iter().cloned().take(2).collect();
+
+    let _: Vec<_> = vec.iter().cloned().skip(2).collect();
+
+    let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
+
+    let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+        .iter()
+        .cloned()
+        .flatten();
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().map(|x| x.len());
+
+    // This would fail if changed.
+    let _ = vec.iter().cloned().map(|x| x + "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().find(|x| x == "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().all(|x| x.len() == 1);
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().any(|x| x.len() == 1);
+
+    // Should probably stay as it is.
+    let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
+}
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
new file mode 100644
index 00000000000..e36b0e36fbd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -0,0 +1,58 @@
+error: called `cloned().last()` on an `Iterator`. It may be more efficient to call `last().cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:7:29
+   |
+LL |     let _: Option<String> = vec.iter().cloned().last();
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().last().cloned()`
+   |
+   = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings`
+
+error: called `cloned().next()` on an `Iterator`. It may be more efficient to call `next().cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:9:29
+   |
+LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().chain(vec.iter()).next().cloned()`
+
+error: called `cloned().count()` on an `Iterator`. It may be more efficient to call `count()` instead
+  --> $DIR/iter_overeager_cloned.rs:11:20
+   |
+LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").count()`
+   |
+   = note: `-D clippy::redundant-clone` implied by `-D warnings`
+
+error: called `cloned().take(...)` on an `Iterator`. It may be more efficient to call `take(...).cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:13:21
+   |
+LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().take(2).cloned()`
+
+error: called `cloned().skip(...)` on an `Iterator`. It may be more efficient to call `skip(...).cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:15:21
+   |
+LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().skip(2).cloned()`
+
+error: called `cloned().nth(...)` on an `Iterator`. It may be more efficient to call `nth(...).cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:17:13
+   |
+LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").nth(2).cloned()`
+
+error: called `cloned().flatten()` on an `Iterator`. It may be more efficient to call `flatten().cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:19:13
+   |
+LL |       let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+   |  _____________^
+LL | |         .iter()
+LL | |         .cloned()
+LL | |         .flatten();
+   | |__________________^
+   |
+help: try this
+   |
+LL ~     let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+LL ~         .iter().flatten().cloned();
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 87cdb3ace47..3208048e0d5 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -176,4 +176,52 @@ mod issue6675 {
     }
 }
 
+mod issue8239 {
+    fn more_than_max_suggestion_highest_lines_0() {
+        let frames = Vec::new();
+        frames
+            .iter()
+            .map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or_default();
+    }
+
+    fn more_to_max_suggestion_highest_lines_1() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or_default();
+    }
+
+    fn equal_to_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            }).unwrap_or_default();
+    }
+
+    fn less_than_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        let map = iter.map(|f: &String| f.to_lowercase());
+        map.reduce(|mut acc, f| {
+            acc.push_str(&f);
+            acc
+        }).unwrap_or_default();
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 3f69cef301c..57ab5f03ee2 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -176,4 +176,54 @@ mod issue6675 {
     }
 }
 
+mod issue8239 {
+    fn more_than_max_suggestion_highest_lines_0() {
+        let frames = Vec::new();
+        frames
+            .iter()
+            .map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or(String::new());
+    }
+
+    fn more_to_max_suggestion_highest_lines_1() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or(String::new());
+    }
+
+    fn equal_to_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or(String::new());
+    }
+
+    fn less_than_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        let map = iter.map(|f: &String| f.to_lowercase());
+        map.reduce(|mut acc, f| {
+            acc.push_str(&f);
+            acc
+        })
+        .unwrap_or(String::new());
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 9d0c42b10c2..549b00ae3c4 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -108,5 +108,57 @@ error: use of `unwrap_or` followed by a function call
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
-error: aborting due to 18 previous errors
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:189:14
+   |
+LL |             .unwrap_or(String::new());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:202:14
+   |
+LL |             .unwrap_or(String::new());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:208:9
+   |
+LL | /         iter.map(|f: &String| f.to_lowercase())
+LL | |             .reduce(|mut acc, f| {
+LL | |                 let _ = "";
+LL | |                 acc.push_str(&f);
+LL | |                 acc
+LL | |             })
+LL | |             .unwrap_or(String::new());
+   | |_____________________________________^
+   |
+help: try this
+   |
+LL ~         iter.map(|f: &String| f.to_lowercase())
+LL +             .reduce(|mut acc, f| {
+LL +                 let _ = "";
+LL +                 acc.push_str(&f);
+LL +                 acc
+LL ~             }).unwrap_or_default();
+   |
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:221:9
+   |
+LL | /         map.reduce(|mut acc, f| {
+LL | |             acc.push_str(&f);
+LL | |             acc
+LL | |         })
+LL | |         .unwrap_or(String::new());
+   | |_________________________________^
+   |
+help: try this
+   |
+LL ~         map.reduce(|mut acc, f| {
+LL +             acc.push_str(&f);
+LL +             acc
+LL ~         }).unwrap_or_default();
+   |
+
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.rs b/src/tools/clippy/tests/ui/return_self_not_must_use.rs
index 7dd5742dae9..9b33ad6d3f6 100644
--- a/src/tools/clippy/tests/ui/return_self_not_must_use.rs
+++ b/src/tools/clippy/tests/ui/return_self_not_must_use.rs
@@ -1,4 +1,5 @@
 #![crate_type = "lib"]
+#![warn(clippy::return_self_not_must_use)]
 
 #[derive(Clone)]
 pub struct Bar;
diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
index 8af10cb65c4..94be87dfa31 100644
--- a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
+++ b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
@@ -1,5 +1,5 @@
 error: missing `#[must_use]` attribute on a method returning `Self`
-  --> $DIR/return_self_not_must_use.rs:7:5
+  --> $DIR/return_self_not_must_use.rs:8:5
    |
 LL |     fn what(&self) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     fn what(&self) -> Self;
    = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
 
 error: missing `#[must_use]` attribute on a method returning `Self`
-  --> $DIR/return_self_not_must_use.rs:17:5
+  --> $DIR/return_self_not_must_use.rs:18:5
    |
 LL | /     pub fn foo(&self) -> Self {
 LL | |         Self
@@ -18,7 +18,7 @@ LL | |     }
    = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
 
 error: missing `#[must_use]` attribute on a method returning `Self`
-  --> $DIR/return_self_not_must_use.rs:20:5
+  --> $DIR/return_self_not_must_use.rs:21:5
    |
 LL | /     pub fn bar(self) -> Self {
 LL | |         self
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index f175700a3f4..5b7e61a349d 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -368,7 +368,7 @@ Otherwise, have a great day =^.^=
         <img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on Github"/>
     </a>
 
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/7.0.0/markdown-it.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/12.3.2/markdown-it.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/highlight.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/languages/rust.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.12/angular.min.js"></script>
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index f039ba59d23..22785013085 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -500,7 +500,19 @@ impl<'test> TestCx<'test> {
             expected = expected.replace(&cr, "");
         }
 
-        self.compare_source(&expected, &actual);
+        if !self.config.bless {
+            self.compare_source(&expected, &actual);
+        } else if expected != actual {
+            let filepath_buf;
+            let filepath = match &self.props.pp_exact {
+                Some(file) => {
+                    filepath_buf = self.testpaths.file.parent().unwrap().join(file);
+                    &filepath_buf
+                }
+                None => &self.testpaths.file,
+            };
+            fs::write(filepath, &actual).unwrap();
+        }
 
         // If we're only making sure that the output matches then just stop here
         if self.props.pretty_compare_only {
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 0f8c96c92689af8378dbe9f466c6bf15a3a2745
+Subproject 9700addc82111200a2150b9a796f62dd8e600dd
diff --git a/src/tools/rust-demangler/tests/lib.rs b/src/tools/rust-demangler/tests/lib.rs
index 5a67b423225..85019df7867 100644
--- a/src/tools/rust-demangler/tests/lib.rs
+++ b/src/tools/rust-demangler/tests/lib.rs
@@ -29,14 +29,14 @@ cc[4d6468d6c9fd4bb3]::spawn::{closure#0}::{closure#0}
 <core[846817f741e54dfd]::slice::Iter<u8> as core[846817f741e54dfd]::iter::iterator::Iterator>::rposition::<core[846817f741e54dfd]::slice::memchr::memrchr::{closure#1}>::{closure#0}
 alloc[f15a878b47eb696b]::alloc::box_free::<dyn alloc[f15a878b47eb696b]::boxed::FnBox<(), Output = ()>>
 INtC8arrayvec8ArrayVechKj7b_E
-<const_generic[317d481089b8c8fe]::Unsigned<11: u8>>
-<const_generic[317d481089b8c8fe]::Signed<152: i16>>
-<const_generic[317d481089b8c8fe]::Signed<-11: i8>>
-<const_generic[317d481089b8c8fe]::Bool<false: bool>>
-<const_generic[317d481089b8c8fe]::Bool<true: bool>>
-<const_generic[317d481089b8c8fe]::Char<'v': char>>
-<const_generic[317d481089b8c8fe]::Char<'\n': char>>
-<const_generic[317d481089b8c8fe]::Char<'∂': char>>
+<const_generic[317d481089b8c8fe]::Unsigned<11u8>>
+<const_generic[317d481089b8c8fe]::Signed<152i16>>
+<const_generic[317d481089b8c8fe]::Signed<-11i8>>
+<const_generic[317d481089b8c8fe]::Bool<false>>
+<const_generic[317d481089b8c8fe]::Bool<true>>
+<const_generic[317d481089b8c8fe]::Char<'v'>>
+<const_generic[317d481089b8c8fe]::Char<'\n'>>
+<const_generic[317d481089b8c8fe]::Char<'∂'>>
 <const_generic[317d481089b8c8fe]::Foo<_>>::foo::FOO
 foo[0]
 foo[0]
@@ -51,14 +51,14 @@ cc::spawn::{closure#0}::{closure#0}
 <core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0}
 alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>
 INtC8arrayvec8ArrayVechKj7b_E
-<const_generic::Unsigned<11: u8>>
-<const_generic::Signed<152: i16>>
-<const_generic::Signed<-11: i8>>
-<const_generic::Bool<false: bool>>
-<const_generic::Bool<true: bool>>
-<const_generic::Char<'v': char>>
-<const_generic::Char<'\n': char>>
-<const_generic::Char<'∂': char>>
+<const_generic::Unsigned<11u8>>
+<const_generic::Signed<152i16>>
+<const_generic::Signed<-11i8>>
+<const_generic::Bool<false>>
+<const_generic::Bool<true>>
+<const_generic::Char<'v'>>
+<const_generic::Char<'\n'>>
+<const_generic::Char<'∂'>>
 <const_generic::Foo<_>>::foo::FOO
 foo[0]
 foo[0]
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 88f5dc43245..5de30129266 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -1,7 +1,7 @@
 use std::iter::ExactSizeIterator;
 use std::ops::Deref;
 
-use rustc_ast::ast::{self, FnRetTy, Mutability};
+use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
 use rustc_ast::ptr;
 use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
@@ -141,7 +141,7 @@ pub(crate) enum SegmentParam<'a> {
     Const(&'a ast::AnonConst),
     LifeTime(&'a ast::Lifetime),
     Type(&'a ast::Ty),
-    Binding(&'a ast::AssocTyConstraint),
+    Binding(&'a ast::AssocConstraint),
 }
 
 impl<'a> SegmentParam<'a> {
@@ -176,9 +176,9 @@ impl<'a> Rewrite for SegmentParam<'a> {
     }
 }
 
-impl Rewrite for ast::AssocTyConstraint {
+impl Rewrite for ast::AssocConstraint {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
-        use ast::AssocTyConstraintKind::{Bound, Equality};
+        use ast::AssocConstraintKind::{Bound, Equality};
 
         let mut result = String::with_capacity(128);
         result.push_str(rewrite_ident(context, self.ident));
@@ -206,11 +206,14 @@ impl Rewrite for ast::AssocTyConstraint {
     }
 }
 
-impl Rewrite for ast::AssocTyConstraintKind {
+impl Rewrite for ast::AssocConstraintKind {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match self {
-            ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape),
-            ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
+            ast::AssocConstraintKind::Equality { term } => match term {
+                Term::Ty(ty) => ty.rewrite(context, shape),
+                Term::Const(c) => c.rewrite(context, shape),
+            },
+            ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
         }
     }
 }